设为首页 加入收藏

TOP

C++对象模型――Copy Constructor 的建构操作(第二章)(二)
2015-11-21 00:56:38 来源: 作者: 【 】 浏览:7
Tags:对象 模型 Copy Constructor 建构 操作 第二章
ject的copy constructor:
// 一个被合成出来的copy constructor
// C++伪代码
inline Word::Word(const Word &wd) {
    str.String::String(wd.str);
    cnt = wd.cnt;
}
有一点值得注意:在这被合成出来的copy constructor中,如整数、指针、数组等等的nonclass members也都会被复制。

不要Bitwise copy Semantics

什么时候一个 class 不展现出bitwise copy semantics呢?有四种情况:
1. 当 class 内含一个member object而后者的 class 声明有一个copy constructor时(不论是被 class 设计者显式声明,或是被编译器合成)
2. 当 class 继承自一个base class 而后者存在有一个copy constructor时
3. 当 class 声明了一个或者多个 virtual functions时
4. 当 class 派生自一个继承串链,其中有一个或者多个 virtual base classe
前两种情况中,编译器必须将members或base class 的copy constructors调用操作插入到被合成的copy constructor中。后两种情况有点复杂,如接下来的小节所述。

重新设定 Virtual Table的指针

编译期间的两个程序扩张操作(只要有一个 class 声明了一个或多个 virtual functions就会如此)
增加一个 virtual function table(vtbl),内含每一个有作用的 virtual function的地址
将一个指向 virtual funtcion table的指针(vptr),插入到每一个 class object中
很显然,如果编译器对于每一个新产生的 class object的vptr不能成功而正确地设好其初值,将导致可怕的后果。因此,当编译器导入一个vptr到 class 中时,该 class 就不再展现bitwise semantics。现在,编译器需要合成出一个copy constructor,以求vptr适当初始化,如下所示:
首先,定义两个classes,ZooAnimal和Bear
class ZooAnimal {
public:
    ZooAnimal();
    virtual ~ZooAnimal();
    virtual void animate();
    virtual void draw();
private:
    // ZooAnimal的animate()和draw()
    // 所需要的数据
};
class Bear : public ZooAnimal {
public:
    Bear();
    void animate();
    void draw();
    virtual void dance();
private:
    // Bear的animate()和draw()和dance()
    // 所需要的数据
};
ZooAnimal class object以另一个ZooAnimal class object作为初值,或Bear class object以另一个Bear class object作为初值,都可以直接靠bitwise copy semantics完成。例如:
Bear yogi;
Bear winnie = yogi;
yogi会被 default Bear constructor初始化,而在constructor中,yogi的vtpr被设定指向Bear class 的 virtual table。因此,把yogi的vptr值拷贝给winnie的vptr是完全的。
当一个base class object以其derived class 内容做初始化操作时,其vptr复制操作也必须保证安全,例如:
ZooAnimal franny = yogi;    // 这会发生切割(sliced)
franny的vptr不可以被设定指向Bear class 的virtual table,否则当下面程序片段中的draw()被调用而franny被传进去时,就会炸毁(blow up)
void draw (const ZooAnimal &zoey) {
    zoey.draw();
}
void foo() {
    // franny的vptr指向ZooAnimal的virtual table
    // 而非Bear的virtual table
    ZooAniaml franny = yogi;
    draw(yogi);        //调用Bear::draw()
    draw(franny);    //调用ZooAnimal::draw()
}
通过franny调用virtual function draw(),调 用的是ZooAnimal实体而非Bear实体(虽然franny是以Bear object yogi作为初始值)。因为franny是一个ZooAnimal object。事实上,yogi中的Bear部分已经在franny初始化时被切割(sliced)。如果franny被声明为一个reference(或者如果它是一个指针,而其值为yogi的地址),那么经由franny所调用的draw()才会是Bear的函数实体。
合成出来的ZooAnimal copy constructor会显式设定object的vptr指向ZooAnimal class 的 virtual table,而不是直接从 class object中将其vptr的值拷贝过来。

处理Virtual Base Class Subobject

Virtual base class 的存在需要特别处理,一个 class object如果以另一个object作为初值,而后者有一个 virtual base class subobject,那么也会使bitwise copy semantics失效。
每一个编辑器对于虚拟继承的支持承诺,都表示必须让derived class object中的virtual base class subobject位置在执行期就准备妥当。维护位置的完整性是编辑器的责任。Bitwise copy semantics可能会破坏这个位置,所以编辑器必须在它自己合成出来的 copy constructor中做出仲裁。例如,在下面的声明中,ZooAnimal成为Raccon的一个virtual base class :
class Raccon : public virtual ZooAnimal {
public:
    Raccon(){ /* 设定private data初值 */ }
    Racccon(int val) { /* 设定private data初值 */ }
    // ...
private:
    // 所需要的数据
};
编译器所产生的代码(用以调用ZooAnimal的default constructor,将Racccon的vptr初始化,并定位出Raccon中的ZooAnimal subject)被插入在两个Raccon constructors之间。
那么memberwise初始化呢?一个 virtual base class 的存在会使bitwise copy semantics无效。其次,问题并不发生于一个class obje
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇插入排序、冒泡排序、选择排序、.. 下一篇poj 1364 King(差分约束)(中等)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: