#ifndef CLAUSE_5_H
#define CLAUSE_5_H
//条款5 了解C++默默编写并调用哪些函数
//知识点:编译器可以暗自为class创建default构造函数,copy构造函数,copy assigment操作符,以及析构函数
//生成时机:惟有这些函数被需要时(调用),它们才会被编译器创建出来。
//但是当打算在一个有reference成员的class内支持赋值操作,你必须自己定义copy assignment操作符,面对内含const成员的classes也一样。
class NameObject{
public:
NameObject(std::string &name,const int& value);
private:
std::string & nameValue;//reference成员
const int objectValue;//const成员
};
std::string newDog("persephone");
std::string oldDog("Satch");
NameObject p(newDog,2);
NameObject s(oldDog,36);
p=s; //这个赋值语句会发生什么?
//因为C++不支持让reference改指向不同的对象,所以编译器拒绝那一行的赋值操作,面对const成员也是一样的。
#endif
#ifndef CLAUSE6_H
#define CLAUSE6_H
//条款6:若不想使用编译器自动生成的函数,就该明确拒绝。
//知识点 为驳回编译器自动提供的机能,可以将相应的成员函数声明为private并且不予实现,当然使用Uncopyable这样的base class也是一种做法
//当我们想让class不存在copy函数和copy assignment的功能时应该怎么做?
//一个关键点:所有编译器产出的函数都是public。所以我们将这些copy函数和copy assignment操作符声明为private就阻止了编译生成其默认版本。而令这些函数为private,使得你得以阻止人们调用它。
//但是这个做法并不绝对安全,因为member函数和friend函数还是可以调用你的private函数。
//所以我们可以将成员函数声明为private而且故意不实现它们。这样在连接的时候连接器就会发出抱怨。
class HomeForSale{
public:
private: //private成员
HomeForSale(const HomeForSale&);
HomeForSale operator=(const HomeForSale&);//只有声明
};
//有了上述class定义,当客户企图拷贝HomeForSale对象,编译器会阻挠他。
//如果你不慎在member函数或friend函数之内那么做,轮到连接器发出抱怨。
//Uncopyable的做法:将连接期错误移至编译期是可能(而且那是好事,毕竟越早侦测出错误越好)
//使用一个专门为阻止copying动作而设计的base class
class Uncopyble{
protected:
Uncopyble(){} //允许derived对象构造和析构
~Uncopyble(){}
private:
Uncopyble(const Uncopyble&); //但阻止copying
Uncopyble& operator=(const Uncopyble&);
};
//为求阻止HomeForSale对象被拷贝,我们唯一需要做的就是继承Uncopyble:
class HomeForSale:private Uncopyble{ //class不再声明,copy构造函数或copy assign操作符
};
//当任何人,包括member函数或者friend函数–尝试拷贝HomeForSale对象,编译便试着生成一个copy函数和一个copy assignment操作符,这些函数的“编译器生成版”会尝试调用其base class的对应兄弟,那些调用会被编译器拒绝,因为其base class的拷贝函数是private
#endif
#ifndef CLAUSE7_H
#define CLAUSE7_H
//条款7:为多态基类声明virtual析构函数
//知识点1 polymorphic(带多态性质的)base classes应该声明一个virtual析构函数。如果class带有任何的virtual函数,它就应该拥有一个virtual析构函数
//知识点2 classes的设计目的如果不是作为base classes使用,或者不是为了具备多态性就不应该声明virtual析构函数
//先看问题:
class TImeKeeper{
public:
TImeKeeper();
~TImeKeeper();
};
class AtomicClock:public TImeKeeper{};
TImeKeeper* ptk=getTimeKeeper();//返回一个指针,指向一个TimeKeeper派生类的动态分配对象
//运用它。。。
delete ptk;
//当删除ptk时,因为base class有个non-virtual析构函数(可能默认使用了基类的析构函数),会发生的是derived成分没被销毁。
//解决办法:给base class添加一个virtual析构函数。此后结果就会正确,在动态调用派生类的析构函数析构派生类对象后,
//编译会调用基类的析构函数析构基类成员(按这个继承层次依次向上调用各基类析构函数)
//如前,如果任何class只要带有virtual函数都几乎确定应该也有一个virtual析构函数。
//但是如果class不含virtual函数,通过表示它并不意图被用做一个base class
//这里详细看书上解释,如果class有virtual函数,它的每一个具体对象应该有指向虚表的虚指针,虚指针增加了内存空间,导致和某些相同结构(不同语言比如C)不能相互移植
//不要继承于拥有non-virtual函数的基类:比如string,包括所有的STL容器如vector,list,set,tr1::unordered_map等等
//放弃继承于标准容器或者任何“带有non-virtual析构函数的类”
#endif