TC++PL4E Chinese and English Edition Errata

TC++PL4E中英版勘误

最近在读The C++ Programming Language Fourth Edition(简称TC++PL4E),由于我入的实体书是中译本(原版好贵),所以我是对照着英文版PDF看的,发现了一些原版和中译本中的勘误,还有一些我觉得书中歧义的地方,查阅标准(ISO/IEC 14882:2014(E))之后的定义也一并贴出,汇总在这里列出来。

**[(E)483]**There are five situations in which an object is copied or moved:
**[(ZH)P414]**一个对象在6种情况下会被拷贝或移动:

**[(E)P488]**This implies that we can prevent destruction of an X by declaring its destructor =delete (§17.6.4) or private.
**[(ZH)P419]**这意味着我们通过声明X的构造函数为=delete(见17.6.4节)或private,就可以阻止其析构。

**[(E)490]**so the value of alpha is {"",””,0}.
**[(ZH)420]**因此alpha的值是{""|,””,0}。

[(E)605]

1
2
class XX : B { /*...*/ }; // B is a private base
struct YY : B { /*...*/ }; // B is a public base

[(ZH)518]

1
2
class XX : B { /*...*/ }; // B是一个公有基类 #此处应该是私有
struct YY : B { /*...*/ }; // B是一个公有基类

下面这个并非翻译错误,原文就是这样(但是关于covariant return的定义和标准中写的不一):
*TCPL(20.3.6 Return Type Relaxation P596)**里covariant return是这么写的:
That is, if the original return type was B
, then the return type of the overriding function may be D*, provided B is a public base of D. Similarly, a return type of B& may be relaxed to D&. This is sometimes called the covariant return rule.

而标准**(ISO/IEC 14882:2014(E) § 10.3 P238)**里是这么写的:
The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. If a function D::f overrides a function B::f, the return types of the functions are covariant if they satisfy the following criteria:

  • both are pointers to classes, both are lvalue references to classes, or both are rvalue references to classes
  • the class in the return type of B::f is the same class as the class in the return type of D::f, or is an unambiguous and accessible direct or indirect base class of the class in the return type of D::f
  • both pointers or references have the same cv-qualification and the class type in the return type of D::f has the same cv-qualification as or less cv-qualification than the class type in the return type of B::f.

If the class type in the covariant return type of D::f differs from that of B::f, the class type in the return type of D::f shall be complete at the point of declaration of D::f or shall be the class type D. When the overriding function is called as the final overrider of the overridden function, its result is converted to the type returned by the (statically chosen) overridden function (5.2.2).

**[(E)P649]**It is not possible to cast to a private base class using static_cast or reinterpret_cast, and ‘‘casting away const’’ (or volatile) requires a const_cast (§11.5.2).
**[(ZH)P553]**我们不可能用dynamic_cast和static转换到私有基类,而“强制去除const”(或volatile)则需要使用const_cast。(见§11.5.2).
这个中译本是对的,因为dynamic_cast和static_cast都不能直接转换到私有基类(compile error:cannot cast ‘Drived’ to its private base class ‘Base’),而reinterpret_cast可以,但是它是对位模式的重新解释,虽然我们用reinterpret_cast将派生类指针转换成了基类的指针,但是底层的位模式上还是派生类,对其操作实际上也是对派生类指针的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Base{
public:
virtual void func(){
cout<<"base function"<<endl;
}
};
class Drived:private Base{
public:
void func(){
cout<<"Drived function"<<endl;
}
};
int main(int argc,char* argv[])
{
Drived *a=new Drived;
// error: cannot cast 'Drived' to its private base class 'Base'
Base *b=dynamic_cast<Base*>(a);
// error: cannot cast 'Drived' to its private base class 'Base'
Base* c=static_cast<Base*>(a);

// 从位模式的解释上改变指针指向的类型
Base *d=reinterpret_cast<Base*>(a);
// OK,output:Base function
d->Base::func();
// OK,output:Drived funtion
d->func();

delete a;
return 0;
}

当我们需要向一个函数传递给一个private基类的指针时使用reinterpret_cast转换很有用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void func(Base* bp){
bp->func();
}
int main(int argc,char* argv[])
{
Drived *a=new Drived;

// compile error: cannot cast 'Drived' to its private base class 'Base'
func(a);

Base *b=reinterpret_cast<Base*>(a);
// OK,output:Drived function
func(b);

delete a;
return 0;
}

更多关于类型转换的内容可以看详细分析下C++中的类型转换

[(E)P663] And [(ZH)P565]

1
2
3
4
5
6
Ship* f(Ship* ps, vector<Ship*>& c)
{
c.push_back(ps); //put the Ship into the container
//...
return c.pop_back(); //retrieve a Ship from the container
}

这里return c.pop_back();这行是不对的,因为vector::pop_back()其定义是void pop_back(),作用是删除容器末尾的元素,且没有返回值。
综合上下文,要实现返回vector容器末尾的元素可以使用*x.rbegin(),即:

1
2
3
4
5
6
Ship* f(Ship* ps, vector<Ship*>& c)
{
c.push_back(ps); //put the Ship into the container
//...
return *c.rbegin(); //retrieve a Ship from the container
}

**[(E)P676]**However, a virtual member function cannot also be a member function template (§23.4.6.2).
**[(ZH)P575]**但是,一个虚成员函数名不能再用作一个成员函数模板名。
这个翻译的有点拗口…其实意思就是成员函数模板不能是虚函数。如:

1
2
3
4
5
6
class Base{
// ...
// 错误,成员函数模板不能为虚函数
template<typename T>
virtual bool intersect(const T&)const =0;
};

详细的原因解释在[(E)P679]和[(ZH)P578]。
以及ISO/IEC 14882:2014(E) §14.5.2 P332

A member function template shall not be virtual.

1
2
3
4
template <class T> struct AA {
template <class C> virtual void g(C); // error
virtual void f(); // OK
};

**[(E)P754]**It would be a good guess that the author of User meant for User::alg()User::algo() to call User::copy().

The article is finished. If you have any questions, please comment and communicate.

Scan the QR code on WeChat and follow me.

Title:TC++PL4E Chinese and English Edition Errata
Author:LIPENGZHA
Publish Date:2016/11/20 21:46
Word Count:3k Words
Link:https://en.imzlp.com/posts/409/
License: CC BY-NC-SA 4.0
Reprinting of the full article is prohibited.
Your donation will encourage me to keep creating!