【整理自用】深入探索c++对象模型(二)

是从第二章开始看起的,通常情况下,如果以后开头没有特殊说明,标题中()里数字代表的是章节序号

1. 默认构造函数在需要的时候构建

1.1 需要的时候:被编译器所需要的时候偷偷构建

情况1: 如果类中包含有一个其他类成员,且这个类成员有默认构造函数。那么编译器构建默认构造函数(事实上相当于是调用该类成员默认构造函数)
注意:其他成员仍然处于未知状态。

例子:

class A
{
    B b;//假设B类有默认构造函数
    int a;
}

A类合成的默认构造函数仅对b作用,a仍然不管他。

情况2:如果显示写出了构造函数,但是未对含有默认构造函数的类成员进行初始化,那么编译器默认补充代码调用它的默认构造函数。
例子:

class A
{
publicA(int x=0):a(x){};
private:
    B b;//假设B、C类有默认构造函数
    C c;
    int a;
}

A类合成的构造函数可以看做为:

A(int x=0)
{
    b.B::B();
    c.C::C();   //按照声明顺序
    a = x;
}

情况3:继承
与情况1类似,带有默认构造函数的基类编译器根据他们的声明次序进行调用。

情况4:含有虚函数
虚函数指针vptr指向哪里是要在构造函数当中做好的,所以如果该类中有虚函数或者继承的基类中有虚函数,那么必须会合成默认构造函数

情况5:
由于虚继承,则基类只有一个副本。
所以其所有的虚继承类,都是生成虚函数表一样的,虚继承类中不直接保存虚拟基类的变量的偏移量,而是保存一个指针。因此,访问变量的时候,必须要这表,那么就会合成默认构造函数。

1.2 拷贝构造函数

< 书写的真是晦涩。。。 >
请问什么叫做:“会以一个object作为class object的初值??” :这句话翻译的这是奇怪,这里应该是说有以下三种情况会调用拷贝构造函数。

针对第一种情况:明确指出用一个对象值作为类另一个对象的初始化。这里需要和赋值函数进行区分。

 class A{};
 A x;
 A xx = x;//调用拷贝构造函数
 class A{};
 A x;
 A xx;
 xx = x;//调用赋值函数

判断是调用赋值函数还是拷贝构造函数,是看看有没有新的类对象生成。

1.2.1 Default memberwise initialization

这里实际上应该是浅拷贝,因为看书上的例子:

class String 
{
public://没有显示的构造函数,这里不翻译容易以为是关键词explicit,不允许隐式转换呢!!!
private:
    char * str;
    int len;
}

String noun("book");
String verb = noun;

根据1.2节,可以判断这里应是调用拷贝构造函数的,默认情况下呢,你看书上是怎么实现的:

verb.str = noun.str;
verb.len = noun.len;

这里是有指针的啊!!!但是没有重新分配一个空间,而是让两个指针的值相等,也就是说是指向同一个地址空间。
这里借用一下博文:https://blog.csdn.net/zssureqh/article/details/7696231里的两张图
图1图1浅拷贝
图2图2深拷贝
仔细观察一下两张图,觉得这里还是非常明确的。


看一下书会发现,下面给的例子是说,如果我们对于那种其他类类型那种需要重新分配空间的类定义了显示拷贝构造函数,那么会先调用这个显示构造函数,然后其他的是按照浅拷贝的方式复制值过来。

1.2.2 什么时候不展现bitwise copy semantics

这个和前面的是类似的。
1. 当class内含一个member object而后者的class声明有一个copy constructor时。(不论是被class设计者明确声明,或是被编译器合成)
2. 当class继承自一个base class而后者存在一个copy constructor时(再次强调,不论是被显式声明或是被合成而得)
3. 当class声明了一个或多个virtual function时
4. 当class派生自一个继承串链,其中有一个或多个virtual base classes时

前两种情况中,编译器必须将member或base class的”copy constructors调用操作”安插到被合成的copy constructor中。

1.2.3 重新设定Virtual Table的指针

当有虚函数的时候,为了实现运行时的多态,意味着必须要设置正确vptr指针!!!!
书上的例子其实只是在说,当派生类初始化基类的时候调用拷贝构造函数的时候,为了保证虚函数指针指向的位置是正确的,因此必然不是简单将派生类vptr值复制过来的!!!
虚继承与第三种情况类似,但是有区别,这里有vbtl,然而vbtl是采用的重新初始化,而不是reset;

1.3 程序转化语意

<这个也是完全看不懂!!!>
写的什么啊。。。第一个假设真实性要根据X的定义来看,那你倒是说什么时候是假的啊。没有说明,只是写编译器是怎么操作的。!!!这些底层编译器的转换和我定义的class到底有什么关系?!

猜你喜欢

转载自blog.csdn.net/wushuomin/article/details/80310630