effective c++读书笔记 条款5 条款6 条款7

本文探讨C++中默认构造函数、复制构造函数、赋值操作符及析构函数的隐式生成与管理策略,强调如何正确处理引用成员与常量成员,并介绍如何避免不必要的编译器默认行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值