class Widget {
public:
Widget(); // default constructor
Widget(const Widget& rhs); // copy constructor
Widget& operator=(const Widget& rhs); // copy assignment operator
...
};
Widget w1; // invoke default constructor
Widget w2(w1); // invoke copy constructor
w1 = w2; // invoke copy
// assignment operator
当你看到什么东西看起来像一个赋值的话,要仔细 阅读,因为 "=" 在语法上还可以被用来调用拷贝构造函数:
Widget w3 = w2; // invoke copy constructor!
幸运的是,拷贝构造函数很容易从拷贝赋值中区别出来。如果一个新的对象被定义(就象上面那行代码中的 w3),一个构造函数必须被调用;它不可能是一个赋值。如果没有新的对象被定义(就象上面那行 "w1 = w2" 代码中),没有构造函数能被调用,所以它就是一个赋值。
拷贝构造函数是一个特别重要的函数,因为它定义一个对象如何通过传值的方式被传递。例如,考虑这个:
bool hasAcceptableQuality(Widget w);
...
Widget aWidget;
if (hasAcceptableQuality(aWidget)) ...
参数 w 通过传值的方式被传递给 hasAcceptableQuality,所以在上面的调用中,aWidget 被拷贝给 w。拷贝动作通过 Widget 的拷贝构造函数被执行。通过传值方式传递意味着“调用拷贝构造函数”。(无论如何,通过传值方式传递用户定义类型通常是一个不好的想法,传引用给 const 通常是更好的选择。)
STL 是标准模板库(Standard Template Library),作为 C++ 的标准库的一部分,致力于容器(containers)(例如,vector,list,set,map,等等),迭代器(iterators)(例如,vector
从 Java 或 C# 那样的语言来到 C++ 的程序员可能会对未定义行为(undefined behavior)的概念感到吃惊。因为各种各样的原因,C++ 中的一些结构成分(constructs)的行为没有确切的定义:你不能可靠地预知运行时会发生什么。这里是两个带有未定义行为的代码的例子:
int *p = 0; // p is a null pointer
std::cout << *p; // dereferencing a null pointer
// yields undefined behavior
char name[] = "Darla"; // name is an array of size 6 (don’t
// forget the trailing null!)
char c = name[10]; // referring to an invalid array index
// yields undefined behavior
为了强调未定义行为的结果是不可预言而且可能是令人讨厌的,有经验的 C++ 程序员常常说带有未定义行为的程序能(can)删除你的硬盘。这是真的:一个带有未定义行为的程序可以(could)删除你的硬盘。只不过可能性不太大。更可能的是那个程序的表现反复无常,有时会运行正常,有时会彻底完蛋,还有时会产生错误的结果。有实力的 C++ 程序员能以最佳状态避开未定义行为。本书中,我会指出许多你必须要注意它的地方。
另一个可能把从其它