关于对象及构造函数语义学

来源:互联网 发布:买淘宝店铺哪个网站 编辑:程序博客网 时间:2024/06/14 07:23

1、C++对象模型

如下类在内存中布局如下:

class Point

{

public:

Point(float xval);

virtual Point();


float x() const;

static int PointCount();


protected:

virtual ostream&print(ostream& os)const;

float  _x;

static int _point_count;

}


1.1 类对象的空间存储着非静态变量和指向虚表的指针(vptr)。虚表(vtbl)中存储着各个virtual函数的地址和用于运行时识别的typeinfo信息

成员函数和静态成员函数,静态变量都属于全局的。



2、C++以下列几种方式完成多态

2.1 由一组隐含的转换操作,如把一个子类指针赋值给基类

CBae* ptrBase = new CDerived

2.2 经由虚函数机制

ptrBase->virtualFun();可以通过函数或引用调用实现,对象之间调用是不行的,因为对象的直接赋值会被裁切。

2.3 经由dynamic_cast 


构造函数语义学

3、默认构造函数的建构操作

合成默认构造函数是给编译器使用,不是给程序员使用,所以成员变量int,char* 编译器是不会给你赋值的。

另外只有以下4中情况编译器才会合成默认构造函数,其它情况是不会合成的。

3.1 成员对象,带有默认构造函数

如果类A包含了类B,而B又有默认构造函数,则此时A会合成一个默认构造函数来调用B的默认构造函数

编译器必须调用每一个成员变量的默认构造函数,如果A已经存在构造函数,则编译器会在该函数中安插B的默认构造函数,代码会插入在用户的代码之前。

如果有多个成员变量,则以声明的顺序进行调用。

3.2 带有默认构造函数的基类

如果A继承自B,而B又有默认构造函数,则A也会合成一个默认构造函数,调用B的构造函数

3.3 带有virtual函数的类

如果A中含有virtual函数,则会合成一个默认构造函数,用以产生虚表,设置指向虚表指针的值。

3.4 带有virtual base class的类

如果A继承B,继承方式是virtual的方式。


4、拷贝构造函数的构建

如果一个class没有提供显示的拷贝构造函数会如何呢。以下情况编译器会依次执行各个对象的拷贝

除了下面几种情况,编译器是不会产生拷贝构造函数的,而直接适用的是按位拷贝,即内存内容的拷贝赋值。

4.1 A含有成员变量B,而B声名了一个拷贝构造函数(可以使用户声名的,也可能是编译器帮忙声名出来的)。此时A就会构建一个拷贝构造函数,去调用B的拷贝构造

4.2 A继承自B,而B含有拷贝构造函数

4.3 A含有virtual函数时

4.4 A继承自B,是通过virtual方式继承的,或则A public继承B,但是B通过virtual方式继承自C

4.1和4.2比较简单,编译器将成员变量或基类的拷贝构造函数插入在默认的拷贝函数中即可。

4.3需要重新设置虚表指针的值。


5、程序转化语义学

X Bar()

{

X xx;

return xx;

}

bar如何将局部对象xx拷贝出来作为返回值呢?编译器的一般做法如下

void Bar(X& _result)

{

X xx;

xx.X::X(); //调用默认构造函数


_result.X::X(xx); // 调用拷贝构造函数

return;

}

如X x1 = Bar();

就会被编译器优化为

X x1;

Bar(x1);

NRV(named return value)优化,如上述函数中,编译器可能直接优化为

void Bar(X& _result)

{

_reult.X::X(); // 直接用result替换xx,调用默认构造函数

// 对_result进行调用出来

return;

}


6、成员的初始化队伍

什么时候必须需要初始化列表

6.1 初始化一个引用成员对象

6.2 初始化一个const成员对象

6.3 调用base class的构造函数,而它的构造函数必须要参数列表‘

6.4 调用成员对象的构造函数,而它必须要有参数

初始化列表的调用顺序是以声明顺序调用的,而不是以列表顺序。初始化列表的调用顺序会在用户代码之前,而编译器插入的成员变量的构造函数和初始化列表的顺序

则视声明顺序来定了





0 0