【深度探索C++对象模型】第二章 构造函数语意学(中)
来源:互联网 发布:单片机12864程序解析 编辑:程序博客网 时间:2024/05/17 08:55
第二章 构造函数语意学(The Semantics of Constructors)(中)
—— 本书作者:Stanley B.Lippman
(接上篇)
三、Copy Constructor 的建构操作
学习目标:
- 什么是 拷贝构造函数(Copy Constructor) ?
- 何时会调用 拷贝构造函数(Copy Constructor)?
- 编译器什么时候会为我们合成一个“有用”的拷贝构造函数?
何时会调用拷贝构造函数(Copy Constructor)?
当一个 对象 通过另一个对象来初始化时,前者的 拷贝构造函数 会被调用。
1. 第一种情况: 初始化。
class X
{
// ...
};
X x; // 定义一个 X 对象
X xx = x; // xx 用 x 来初始化,但如果是: X xx; xx = x; 这里调用的就是 operater = 了,原因很明显,前面才是初始化,这里是赋值。
2. 第二种情况:对象 作为函数参数。extern void foo(X x);
void bar()
{
X xx;
// 以 对象 xx 作为 foo(X x) 的参数x的初值。会调用 x 的Copy Constructor,这里的 x 是一个临时对象。
foo(xx);
}
3. 第三种情况:对象 作为函数返回值。X foo_bar()
{
X xx;
// ...
return xx;
}
拷贝构造函数的表现形式:class X
{
X( const X& x);
// 也可能是多参形式,第二个参数及其后的参数有默认值
// 也可能是多参形式,第二个参数及其后的参数有默认值
// X( const X& x, int other = 0);
}
Default Memberwise Initialization 如果你没有给你的 class 显示的定义 拷贝构造函数,那么在发生需要调用拷贝构造函数的情形时,内部是通过 default Memberwise Initialization 手法完成的。
Default Memberwise Initialization 看起来像什么样子呢?
class A
{
public:
A(const A& a);
private:
int a;
int b;
}
// 编译器合成的 Copy Constructor 可能像这样:
A::A(const A& a)
{
this->a = a.a;
this->b = a.b;
}
【注】当你的类里有指针成员的时候,要格外小心。具体什么问题,可参考 Effective C++ 里的条例。
当我们没有显示定义 拷贝构造函数 时,编译器什么时候才会为我们合成一个?
当一个 class 没有显示定义 copy constructor 的时候,编译器会在必要的时候为这个class合成出来。所谓的必要时,是指 class 没有展现出 Bitwise Copy Semantics(位逐次拷贝) 时。而当 class 展现出 位逐次拷贝 时,并不需要合成一个 Copy Constructor,默认的 Memberwise Initialization 就已足够(但有风险:指针问题)。
1. 当 class 内含一个 成员对象,且该成员对象的类声明有一个 copy constructor 时(不一定是明确声明的,也可能是由编译器合成的 copy constructor)。如,你的 class 里有一个 std::string 成员时(std::string 的copy constructor 不是合成的,是明确声明的),这时如果你没有明确声明一个 copy constructor 编译器会为你合成一个。
2. 当 class 继承自一个 base class ,而后者存在一个 copy constructor 时(合成的或者声明的都算)。
3. 当 class 声明了一个或多个 virtual functions 时。
4. 当 class 的继承串链中,其中有一个或者多个 virtual base classes 时。
重新设定 Virtual Table 的指针__vptr
前面曾学到过,C++对象模型是如何支持 virtual 机制的。是通过在 class 内安插了一个 vptr 指向其相应的 vtbl。因此,如果编译器不能正确的初始化 vptr,将导致严重的后果。所以,当一个 class 有 virtual functions 时,就不在展现出 Bitwise semantics。于是编译器将会合成一个 copy constructor 来初始化 vptr。下面是列子。
【注】一个 class 对应一个 vtbl。相同 class 的 objects 的 vtbl 相同,也即 vptr 指向的地址相同。
class Base
{
public:
Base();
virtual ~Base(); // 基类的析构函数一定要 virtual,否则会导致严重后果。
virtual void draw();
};
class Derive : public Base
{
public:
Derive();
void draw(); // 虽没写明 virtual,但实际上是 virtual。
};
Derive yogi;
Derive winnie = yogi; // OK! winnie 和 yogi 的 vtbl 地址相同。可以直接拷贝 vptr 的值。
Base franny = yogi; // 注意,franny 的 vptr 和 yogi 的 vptr 指向不同的 vtbl,因此,copy contructor 需要重新设定 franny 的值,防止其指向 Derive 的vtbl.
// 这里还涉及到以子类初始化基类时的切割问题
也就是说:合成出来的 Base class 的拷贝构造函数会明确设定其对象的 vptr 指向 Base class 的 vtbl,而不是直接从右手边的 class object 中的 vptr 地址拷贝过来。 处理 Virtual Base Class Subobject
对于虚拟继承(即:继承自一个虚基类),编译器必须维护 派生类中虚基类的位置(要理解这个“位置”的含义,首先你的了解继承后的对象模型是怎样的)。
直接按位拷贝可能会破坏这个"位置"。
class Raccoon : public virtual ZooAnimal
{
// ...
}
class RedPanda : public Raccoon
{
// ...
}
当我们以一个Raccoon对象作为另一个Raccoon对象的初值时,不会有任何问题,默认的Bitwise semantics就足以搞定。但当我们以Derived class:RedPanda作为Raccoon的初值时,就需要编译器合成出一个 拷贝构造函数,以正确的通过 RedPanda(子类) 初始化 Raccoon(父类) 。【说明】近期项目上线,工作较忙,更新像蜗牛!后续加快节奏!
0 0
- 【深度探索C++对象模型】第二章 构造函数语意学(中)
- 【深度探索C++对象模型】第二章 构造函数语意学(上)
- 《深度探索C++对象模型》读书笔记第二章:构造函数语意学
- 《深度探索C++对象模型》第二章 构造函数语意学
- 深度探索C++对象模型 之 构造函数语意学
- 深度探索C++对象模型 2构造函数语意学
- 《深度探索C++对象模型》--2 构造函数语意学
- 第2章 构造函数语意学-《深度探索C++对象模型》读书笔记
- 《深度探索C++对象模型》- 第2章 构造函数语意学
- 【深度探索C++对象模型读书笔记】【第2章】构造函数语意学
- 深入探索C++对象模型 第二章 构造函数语意学
- 深入探索C++对象模型:第二章构造函数语意学
- 《深入探索C++对象模型》第二章:构造函数语意学(上)
- 《深入探索C++对象模型》第二章:构造函数语意学(下)
- 《深入探索C++对象模型》读书笔记——第二章 构造函数语意学
- C++对象模型 第二章 构造函数语意学
- 《深度探索C++对象模型》读书笔记之构造函数语意学
- 深度探索C++对象模型学习 之 C++构造函数语意学(一)
- 互联网行业薪酬等级!看看你值多少钱?
- [Sqlite] --> Sqlite在Windows、Linux 和 Mac OS X 上的安装过程
- lua和luabind编译测试使用
- 理解RESTful架构
- eclipse打开含中文properties文件乱码解决
- 【深度探索C++对象模型】第二章 构造函数语意学(中)
- 示例演示“距离矢量路由算法”工作原理
- BeanUtils的使用
- Replace the SSL Certificate for HP System Management homepage with a CA generated one
- oracle null值处理函数
- 算法笔记--直接插入排序
- Codeforces 17A Noldbach problem(数学)
- Kuwan
- Kuwan