Accelerated C++示例程序在Microsoft Visual C++ 6.0编译环境下已知的问题(Part1)
时间:2010-10-11 来源:Eric Win
最近在阅读Andrew Koeing经典的C++入门书Accelerated C++,本科时学校用的是谭老的《C++程序设计》,当时学得云里雾里,挣扎着把C++这门课PASS了就再没碰过。现在因为学习MFC编程,又把谭老的那本红皮C++书翻出来看,结果还是云里雾里,多态看了N遍还是不解,不禁感慨国内科技图书的编写者水平就是高,联系之前选书的经验,觉悟到像我这种菜鸟还是比较适合看老外写的书。GOOGLE了一圈,大牛们普遍推荐这本Accelerated C++,本来想网购,结果发现居然绝版了,Faint~,还好书店有卖的 :)。
读到第3章的时候,编译测试书中的例程,把书上的程序敲进去,编译运行居然有错误。以为是我敲错了,反复查了几遍,还是有错误,晕。源代码以及编译信息如下:
#include <algorithm> #include <iomanip> #include <ios> #include <iostream> #include <string> #include <vector> using std::cin; using std::sort; using std::cout; using std::streamsize; using std::endl; using std::string; using std::setprecision; using std::vector; int main() { // ask for and read the student's name cout << "Please enter your first name: "; string name; cin >> name; cout << "Hello, " << name << "!" << endl; // ask for and read the midterm and final grades cout << "Please enter your midterm and final exam grades: "; double midterm, final; cin >> midterm >> final; // ask for and read the homework grades cout << "Enter all your homework grades, " "followed by end-of-file: "; vector<double> homework; double x; // invariant: homework contains all the homework grades read so far while (cin >> x) homework.push_back(x); // check that the student entered some homework grades typedef vector<double>::size_type vec_sz; vec_sz size = homework.size(); if (size == 0) { cout << endl << "You must enter your grades. " "Please try again." << endl; return 1; } // sort the grades sort(homework.begin(), homework.end()); // compute the median homework grade vec_sz mid = size/2; double median; median = size % 2 == 0 ? (homework[mid] + homework[mid-1]) / 2 : homework[mid]; // compute and write the final grade streamsize prec = cout.precision(); cout << "Your final grade is " << setprecision(3) << 0.2 * midterm + 0.4 * final + 0.4 * median << setprecision(prec) << endl; return 0; }
------------Configuration: CALCULATING STUDENT GRADES - Win32 Debug------------
Compiling...
CALCULATING STUDENT GRADES.CPP
d:\c++_projects\chapter 3\3-0-1 calculating student grades using middle grade\calculating student grades.cpp(37) : error C2653: 'vector<double,class std::allocator<double> >' : is not a class or namespace name
d:\c++_projects\chapter 3\3-0-1 calculating student grades using middle grade\calculating student grades.cpp(37) : error C2146: syntax error : missing ';' before identifier 'vec_sz'
d:\c++_projects\chapter 3\3-0-1 calculating student grades using middle grade\calculating student grades.cpp(37) : error C2065: 'vec_sz' : undeclared identifier
d:\c++_projects\chapter 3\3-0-1 calculating student grades using middle grade\calculating student grades.cpp(38) : error C2146: syntax error : missing ';' before identifier 'size'
d:\c++_projects\chapter 3\3-0-1 calculating student grades using middle grade\calculating student grades.cpp(38) : error C2065: 'size' : undeclared identifier
d:\c++_projects\chapter 3\3-0-1 calculating student grades using middle grade\calculating student grades.cpp(49) : error C2146: syntax error : missing ';' before identifier 'mid'
d:\c++_projects\chapter 3\3-0-1 calculating student grades using middle grade\calculating student grades.cpp(49) : error C2065: 'mid' : undeclared identifier
Error executing cl.exe.
CALCULATING STUDENT GRADES.exe - 7 error(s), 0 warning(s)
仔细阅读Debug的信息,发现是由于typedef vector<double>::size_type vec_sz;这条语句引起的,其他6条错误是这条错误的副作用。
在CSDN的论坛里翻了一遍,发现原来是编译器的问题。原来Visual C++ 6.0对C++标准支持得不是很好,所以书中的示例程序会有编译错误。“珍爱生命,远离VC6。”看来此话不是空穴来风。GOOGLE的时候很偶然地发现AC++的官网有关于VC++ 6.0不兼容问题的说明。因为是网页是英文的,所以我把它翻译了一下,希望对正在学习这本书而且又在用可恶的VC 6.0的朋友们有所帮助。
题目和本文题目一致,在此不再重复。全文如下:
请注意微软在Visual Studio.NET中已经修复了下文提到的所有问题,因此,仅当你使用早期的6.0版本时下列信息才对你有帮助。
Microsoft Visual C++ 6.0编译器(以下简称VC++6.0)对C++标准的某些方面支持得不好,这使得Accelerated C++此书中的某些例程无法顺利编译通过。本文列举了此类问题,并告诉你如何修改书中原来的代码以避免此类问题的出现。
这些问题中的一部分在整本书中都会重复出现。举个例子,任何影响学生成绩统计程序(即本文前文所提到的那个例子)的问题都将在第4、6、9和13章中出现,因为这个程序在所有其他的章节都会出现。我们首先描述那些普遍存在的问题(pervasive problems),然后在其后列出在每章中出现的特殊问题(specific problems)。
我们已经把这些问题(bug)报告给了微软,其工作人员正在致力于解决这些问题。举例来说,在描述普遍问题的第一部分,其中的问题#2在补丁包4(Service Pack 4)中已经被解决。
我们在每个例子中都提供了一个建议的替代方案(workaround)。这些替代方案通常使用#ifdef预处理命令,它和我们在§4.3/67中所讲解的#ifndef是类似的。如果在#ifdef它后面的预处理符号(the preprocessor symbol)被定义了,那么#ifdef命令会要求预处理器执行从#ifdef到对应的#endif之间的代码。微软的编译器定义了这个符号_MSC_VER作为预处理符号,我们用它来做测试,以使用条件包含(conditionally include)的功能。
普遍性问题(Pervasive bugs):
(1)当你为一个容器类型(container type)写一个using声明时,比如vector类型:
using std::vector;
那么你就可以使用这个容器类型的成员了,尤其是类型成员,而不需要再费力做别的事情。比如:
vector<double>::size_type n = 0;
糟糕的是,VC++6.0却无法编译通过,它会抱怨类似下面这样的一句话:
vector<double, class std::allocator<double> > : is not a class or namespace name
解决此问题最简单的权宜之计就是把std::包含进来,作为一个明确的修饰语,即使根本就没这个必要。
using std::vector; #ifdef _MSC_VER std::vector<double>::size_type n = 0; #else vector<double>::size_type n = 0; #endif
(2)补丁包4之前的VC++ 6.0不能很好地不会函数实参(function arguments)传递给模板函数(template functions)。这个问题会影响学生成绩统计这个在本书中会大量复现的程序。如果你像下面这样把compare作为一个实参传递给标准库sort函数的话,那么这个问题就会出现。
sort(vs.begin(), vs.end(), compare);
解决办法就是为Student_info定义<操作符,这样sort就可以自动使用它了。首先恰当地定义那个函数:
#ifdef _MSC_VER bool operator<(const Student_info& x, const Student_info& y) { return x.name() < y.name(); } #endif
然后像下面这样替换相关的调用(call):
#ifdef _MSC_VER sort(vs.begin(), vs.end()); #else sort(vs.begin(), vs.end(), compare); #endif
还有一个更简单的办法,但是得用到直到第10章才会出现的语言特性。方法就是在compare的前面放一个明确的&操作符:
#ifdef _MSC_VER sort(vs.begin(), vs.end(), &compare); #else sort(vs.begin(), vs.end(), compare); #endif
我们相信补丁包4已经修复了这个问题。
未完待续