MoreEffectiveC++笔记 7技巧

1构造函数和非成员函数虚拟化

虚拟构造函数不是指把构造函数用virtual修饰。对象没有构造完成,不会产生多态的效果。这里是说构造函数调用一个工厂函数,产生的对象会作为这个类的成员,工厂函数会根据输入参数的不同动态生成不同的子类(因为能生成不同类型子类对象所以书里面叫他虚拟构造函数)。类似的可以定义虚函数clone作为虚拟拷贝构造函数完成多态复制。
虚拟化非成员函数就是让非成员函数内联然后调用一个虚函数实现多态。

2限制某个类能产生的对象数目

对象的数目
0个就是构造函数私有并不添加其他可能返回新对象的函数;1个需要补充返回一个静态局部对象的函数,这个函数不能内联,否则局部对象会在代码中多次替换出现产生多个副本。
如果多个的话就需要定义类变量存储当前对象的数目,达到数目后应当抛出异常。
避免继承和聚合产生未预期的数目变化可能需要定义的类不可被继承或者作为其他类的成员,解决这种问题同样可以根据private的构造函数来实现,再补充一个产生对象的伪构造函数来返回对象的指针来生成对象。
最后我们可以把上面的戴安吗封装到一个基类模板里面,需要这种功能的类继承并具现化这个模板获得计数等功能。数目上限存储在静态常量整形中,所有继承模板的类都需要各自初始化这个整形。

3要求或禁止在堆上生成对象

要求在堆上生成对象
让析构函数变成私有或者protect并提供伪析构函数执行delete this。这样使用该类对象作为成员时只能使用这个类的指针。
禁止在堆上生成对象
将operator new设置为私有或者保护的,这样派生类也无法在堆上生成,因为派生类如果没有重载op new的话会继承基类的op new。
没有跨平台语言层面的办法可以稳定判断一个对象在堆上还是在栈上,更改代码去掉这种逻辑

4灵巧指针(智能指针)

记录几个感兴趣的问题

  • 如何满足if(ptr) 这种语法?重载void*转换操作符,或者重载bool转换操作符。需要考虑不同类型具现化的智能指针进行比较可能带来的隐转问题。
  • c++11unique或者shared智能指针都支持多态,可以用基类智能指针保存派生类的指针。
  • static_pointer_cast()、const_pointer_cast()、dynamic_pointer_cast()用于sharedptr的转型(直接用cast转型会导致计数失效)。
  • //todo 补充C++11智能指针的内容,书中讲的是自己实现智能指针的方案。

5引用计数

记录几个感兴趣的问题

  • 写时拷贝:写入的时候要产生一个深拷贝副本的情况,原始的引用减一,再生成一个新的拷贝引用为1次。这是满足lazy原则的方法。shared_ptr使用等号用make_shared或者move来的uniqueptr进行赋值会产生这种结果,直接用等号p1 = p2是增加引用计数。
  • //todo 补充C++11智能指针的内容,书中讲的是自己实现智能指针的方案。

6代理类

给出实现动态二维数组array2d类的例子,这个类重载[]符号返回一个array1d对象,1d同样重载[]符号返回元素,从而实现“[3][6]”这种语法。这里的array1d就是概念上不存在的类,使用2d的代码中完全不会用到这个类。所以这就算一个代理类。
代理类判断[ ]返回值作为左值还是右值使用
例如一个string类用[]下标提取一个字符,如果是s[i] = 'a’就是作为左值被写入;如果是cout<<s[i]就是被作为右值进行读取。需要在string的类内能够对两种情况进行区分,方案就是实现嵌套代理类charproxy放置在string类体内。代理类定义op (char)隐转操作符处理读操作;定义charproxy(char c)单参数的构造函数处理写入操作。
这种方案存在缺陷,就是当作为右值需要取它的地址的时候,得到的会是代理类的指针,如果需要解决这个问题那么就还要实现一个取地址符号的重载;当作为左值的时候不支持+=或者++这种操作。

7根据一个以上的对象进行虚拟

在某种场景下,继承同一个基类的多种派生类对象同时输入到一个函数内:void foo(Base& b1, Base& b2)输入的会是两个派生类,要根据子类的不同动态决定执行策略,数目会是子类种类的平方。这种场景称为double dispatch(二重调度)

方案1:多态加rtti

就是第一个参数用多态完成,第二个参数需要if else if else if对typeid进行判断执行不同的结果。
缺点就是每当新加一个类我们的else if 就要新添加一块。

方案2:虚函数和参数多态

void foo(Base& b1, Base& b2){
	b1._foo(b2);
C1::_foo(Base& B){
	b.foo(*this);
}
C1::_foo(C1& c);
C1::_foo(C2& c);

缺点和上一种类似,多一个子类就要每个子类里面多写一个重载的成员函数。

方案3:设置成员函数指针模拟虚函数表

//略

方案4:非成员函数

不把函数作为成员可以避免每次更改都要导致所有类都需要重新编译。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值