有學生向我求助,他編了一個程序,設計一個“點”類,求出兩點距離的程序。程序看著沒有問題,卻出了一大堆的錯誤。程序如下:
~~~
#include <iostream>
#include <math.h>
using namespace std;
class point
{
public:
double x;
double y;
};
double distance(point p1,point p2);
int main()
{
point p1= {3,5},p2= {6,9};
cout<<distance(p1,p2);
}
double distance(point p1,point p2)
{
double d=sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
return d;
}
~~~
在codeBlocks下編譯,錯誤直接引到stl_iterator_base_types.h文件中,錯誤一大堆:
~~~
||=== example, Debug ===|
D:\C++\codeBlock\example\example.cpp|15|instantiated from here|
d:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_iterator_base_types.h|127|error: no type named 'iterator_category' in 'class point'|
d:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_iterator_base_types.h|128|error: no type named 'value_type' in 'class point'|
d:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_iterator_base_types.h|129|error: no type named 'difference_type' in 'class point'|
d:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_iterator_base_types.h|130|error: no type named 'pointer' in 'class point'|
d:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_iterator_base_types.h|131|error: no type named 'reference' in 'class point'|
||=== Build finished: 5 errors, 0 warnings ===|
~~~
對于這樣的問題,初學C++的同學肯定直接蒙。這里的問題出在命名空間中名字的沖突,再多說一些,與STL也有些關系。不過,解決這樣的問題并不一定得知道這么多。我還是試著與大家繞開這個環節,從其他途徑找點感覺。
光標置到“D:\C++\codeBlock\example\example.cpp|15|instantiated from here|”一行,雙擊,發現錯誤在程序的第15行。鼠標放到15行的distance函數上時,浮現出了一行提示,見圖:

看出了一點疑惑:distance不是在這個程序中編的自定義函數嗎?怎么識別成了std::distance(...,...)?
這就是問題的根源!編譯器沒有將distance當作自定義函數處理!至于進一步的解釋不再深入,抓住這個要點,程序就可以改好了。
**修改方法之一:**既然函數名字上出問題,試試改個名字?將distance改個名字,如dist,一切正常。
**修改方法之二:**憑什么讓我改?distance多好的一個函數名(不過提醒,可以自學一下命名空間了,此是好機會,不必等著老師講。)需要做的工作是,不用std命名空間(刪除或注釋掉using namespace std;一行)然后在依賴std的cout前加上std::,程序如下:
~~~
#include <iostream>
#include <math.h>
//using namespace std;//不再用命名空間std
class point
{
public:
double x;
double y;
};
double distance(point p1,point p2);
int main()
{
point p1= {3,5},p2= {6,9};
std::cout<<distance(p1,p2); //保證編譯系統知道用std命名空間中的cout
}
double distance(point p1,point p2)
{
double d=sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
return d;
}
~~~
**修改方法之三:**方法二有點自私了。std中有不少常用的東東,就此全都得寫std::,這個程序中無妨,如果再大些的程序呢?胳膊不必和大腿擰,換種思路,也是一樣。將distance在調用時,寫作為::distance,指出distance是當前程序中定義的名字。問題解決就此解決,程序如下:
~~~
#include <iostream>
#include <math.h>
using namespace std;
class point
{
public:
double x;
double y;
};
double distance(point p1,point p2);
int main()
{
point p1= {3,5},p2= {6,9};
cout<<::distance(p1,p2);//指定distance不是別處的,就是本文件中定義的
}
double distance(point p1,point p2)
{
double d=sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
return d;
}
~~~
**修改方法之四:**前三種方法中,個人傾向于第一種,山不轉水轉,換個名字也妨。其實這也不是最好的。原始的程序中定義了類,但只有數據成員,沒有成員函數,像求距離之類的,設計為成員函數多好。面向對象的機制就是為了信息封裝等特性的,為何要如此浪費?這個程序我就不寫了,請自行解決。
**補充:**用其他編程環境時,觀察和修改的方法也類似,例如在VS2008下編譯,錯誤居然有25個之多:
~~~
1>------ 已啟動生成: 項目: example, 配置: Debug Win32 ------
1>正在編譯...
1>example.cpp
1>d:\program files\microsoft visual studio 9.0\vc\include\xutility(764) : error C2039: “iterator_category”: 不是“point”的成員
1> d:\c++\vs2008 project\example\example\example.cpp(5) : 參見“point”的聲明
1> d:\c++\vs2008 project\example\example\example.cpp(16): 參見對正在編譯的類 模板 實例化“std::iterator_traits<_Iter>”的引用
1> with
1> [
1> _Iter=point
1> ]
(此處省略N多的提示)
1>生成日志保存在“file://d:\C++\VS2008 project\example\example\Debug\BuildLog.htm”
1>example - 25 個錯誤,0 個警告
========== 生成: 成功 0 個,失敗 1 個,最新 0 個,跳過 0 個 ==========
~~~
在源程序中,鼠標光臨distance函數時,可以看出編譯器對distance函數有兩種解釋,如下圖:

編譯器對此局面真的很迷茫了。余下的修改思路相同,不再羅嗦。