条款05: Kown what functions C++ silently writes and calls.
class Empty {
};
等价于如下的类
class Empty{
public
Empty(){
};
Empty(const Empty& rhs){
}
~Empty(){
}
Empty operation = (const Empty& rhs) {
}
};
下面代码造成上述每一个函数被编译器产出:
Empty e1; // default构造函数
// 析构函数
Empty e2(e1); // copy构造函数
e2 = e1; // copy assignment操作符
区分一下拷贝构造与拷贝赋值:
<pre name="code" class="cpp">#include <iostream>
using namespace std;
class CompareCopyAssignAndCopyCtr{
public:
CompareCopyAssignAndCopyCtr(){
cout << "CompareCopyAssignAndCopyCtr"<< endl;
};
~CompareCopyAssignAndCopyCtr(){
cout << "~CompareCopyAssignAndCopyCtr"<< endl;
};
CompareCopyAssignAndCopyCtr(const CompareCopyAssignAndCopyCtr&){
cout << "Copyctr"<< endl;
};
CompareCopyAssignAndCopyCtr& operator=(const CompareCopyAssignAndCopyCtr&){
cout << "Copyassign"<< endl;
return *this;
};
};
int main(int argc, char** argv) {
CompareCopyAssignAndCopyCtr c1;
CompareCopyAssignAndCopyCtr c2;
cout << "---------------------"<< endl;
CompareCopyAssignAndCopyCtr c3(c2); //copy ctr
cout << "---------------------"<< endl;
c2 = c1; //copy assign
cout << "---------------------"<< endl;
CompareCopyAssignAndCopyCtr c4 = c1; //copy ctr
cout << "---------------------"<< endl;
return 0;
}
运行结果如下:
#include <iostream>
using namespace std;
template<class T>
class NamedObject{
public:
NamedObject(const string& name, const T& value);
void printInfo();
private:
string nameValue;
T objectValue;
};
template<class T>
NamedObject<T>::NamedObject(const string& name, const T& value){
nameValue = name;
objectValue = value;
};
template<class T>
void NamedObject<T>::printInfo(){
cout << "NamedObject's Name is " << nameValue << endl;
};
int main(int argc, char** argv) {
string newDog("Lucky");
string oldDog("Hasq");
NamedObject<int> p(newDog, 2);
NamedObject<int> s(oldDog, 36);
p.printInfo();
s.printInfo();
p = s;
p.printInfo();
s.printInfo();
return 0;
}
运行结果如下:
如果调用默认的构造函数
int main(int argc, char** argv) {
NamedObject<int> m;
return 0;
}
编译报错:
[Error] no matching function for call to 'NamedObject<int>::NamedObject()'
由于其中声明了一个构造函数,编译器于是不再为它创建default构造函数。为了说明这一点,再举一个例子
using namespace std;
class Fruit {
public:
Fruit(int id);
string s;
};
Fruit::Fruit(int id){
};
class Apple: public Fruit {
public:
Apple();
};
Apple::Apple(){
};
int main () {
Apple apple;
}
编译报错:
[Error] no matching function for call to 'Fruit::Fruit()'
#include <iostream>
using namespace std;
template<class T>
class NamedObject{
public:
NamedObject(string& name, const T& value);
void printInfo();
private:
string& nameValue;
const T objectValue;
};
template<class T>
NamedObject<T>::NamedObject(string& name, const T& value): nameValue(name), objectValue(value) {
}
template<class T>
void NamedObject<T>::printInfo(){
cout << "NamedObject's Name is " << nameValue << endl;
};
int main(int argc, char** argv) {
string newDog("Lucky");
string oldDog("Hasq");
NamedObject<int> p(newDog, 2);
NamedObject<int> s(oldDog, 36);
p.printInfo();
s.printInfo();
p = s;
p.printInfo();
s.printInfo();
return 0;
}
编译报错:
[Error] non-static reference member 'std::string& NamedObject<int>::nameValue', can't use default assignment operator
[Error] non-static const member 'const int NamedObject<int>::objectValue', can't use default assignment operator
结论:
①如果打算在一个“内含reference 成员”的class类支持赋值操作,必须自己定义copy assignment 操作符
②面对“内含const成员”的class类,编译器的反应也是一样。
条款06: Explicitly disallow the use of complier-generated functions you do not want.
class HomeForSale{
};
int main(int argc, char** argv) {
HomeForSale h1;
HomeForSale h2;
HomeForSale h3(h1); //企图拷贝h1 --期望不该通过编译
h1 = h2; //企图拷贝h2 --期望不该通过编译
return 0;
}
为实现阻止拷贝的作用,可将相应的成员函数声明为private并且不予实现。
class Uncopyable{
protected:
Uncopyable(); //允许derived对象构造和析构
~Uncopyable();
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
Uncopyable::Uncopyable(){
};
Uncopyable::~Uncopyable(){
};
class Child: public Uncopyable{
};
int main(int argc, char** argv) {
Child child1;
Child child2;
Child child3(child2);
child2 = child1;
return 0;
}
此时编译报错:
[Error] 'Uncopyable::Uncopyable(const Uncopyable&)' is private
[Error] 'Uncopyable& Uncopyable::operator=(const Uncopyable&)' is private
条款07: Declare destructors virtual in polymorphic base classes
#include <iostream>
using namespace std;
class TimeKeeper{
public:
TimeKeeper(){
cout << "TimeKeeper" << endl;
};
~TimeKeeper(){
cout << "~TimeKeeper" << endl;
};
};
class AtomicClock: public TimeKeeper{
public:
AtomicClock(){
cout << "AtomicClock" << endl;
};
~AtomicClock(){
cout << "~AtomicClock" << endl;
};
};
class WaterClock: public TimeKeeper{
};
class WristWatch: public TimeKeeper{
};
TimeKeeper* getTimeKeeper(int type){
TimeKeeper* temp = NULL;
switch(type)
{
case 1:
temp = new AtomicClock();
break;
case 2:
temp = new WaterClock();
break;
case 3:
temp = new WristWatch();
break;
default:
break;
}
return temp;
};
int main(int argc, char** argv) {
TimeKeeper* ptk = getTimeKeeper(1);
delete ptk;
return 0;
}
运行结果如下:
补充:构造和析构函数链
int main(int argc, char** argv) {
AtomicClock ac;
return 0;
}
运行结果如下:
结论:
当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,实际执行时通常发生的是对象的derived成分没有被销毁。
改进做法,将析构函数声明为virtual函数即可,如下所示。
class TimeKeeper{
public:
...
virtual ~TimeKeeper(){
cout << "~TimeKeeper" << endl;
};
};
运行结果如下:
注意:
①带有多态(polymorphic)性质的base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数(???)。
②classes的设计目的如果不是作为base classes使用,或不是为了具备多态性(polymorphically),就不该声明virtual析构函数
条款 08:Prevent exceptions from leaving destructos
#include <iostream>
using namespace std;
class DBConnection{
public:
static DBConnection create(){
DBConnection dbc;
cout << "Connection Success!" << endl;
return dbc;
};
void close(){
cout << "Connection Close!" << endl;
};
};
class DBConn{
public:
DBConn(){
db = DBConnection::create();
}
void close(){ //供客户使用的新函数
db.close();
closed = true;
};
~DBConn()
{
if (!closed) {
try {
db.close(); //关闭连接(如果客户没有显示调用close()函数的话)
}
catch(...){ //如果关闭动作失败,记录下来并结束程序或吞下异常
//制作运转记录,记下对close的调用失败
}
}
};
private:
DBConnection db;
bool closed;
};
int main(int argc, char** argv) {
DBConn dbconn;
return 0;
}
运行结果如下:
注意:
①析构函数绝对不要吐出异常。
②如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。