C++对象模型 第二章 构造函数语意学



1)explict主要用于修饰构造函数,能够制止“单一参数的constructor”被当做一个conversion运算符。
class myclass
{
public:
myclass(int num);
}
myclass obj=10;//ok,convert int to myclass




2)默认拷贝构造函数

默认构造函数(default constructor)就是在没有显式提供初始化式时调用的构造函数。它由不带参数的构造函数,或者为所有的形参提供默认实参的构造函数定义。如果定义某个类的变量时没有提供初始化式就会使用默认构造函数。如 Base b;

默认构造函数的构造操作

“默认构造函数在需要的时候被编译器产生出来”
这里进行区分:如果是程序需要,那么这是程序员的责任。如果是编译器需要,那么就会合成默认构造函数。


class Foo
{
public :
int val;
Foo* pnext;
};
在这个例子中,正确的程序语意是要求Foo有一个defaul constructor,可以将它的两个members初始化为0。这是程序员需要而非编译器需要。


可以这么说,一个被隐式声明出来的default constructor将是一个trivial constructor(无用的构造函数)


3)
Global objects全局对象的内存保证会在程序启动的时候被清零。
Local objects配置于程序堆栈中,heap objects配置与自由空间中,都不一定会清零,它们的内容将是内存上次使用后的遗迹。




4)一个有用的默认构造函数就是编译器所需要的那种。下面讨论有用默认构造函数。
①带有default constructor的member class object(**内含对象***)
如果一个类没有构造函数,但它内含一个member object(类成员对象),而后者有默认构造函数,那么这个类的implicit default constructor(隐式定义的缺省构造函数, 隐式定义的缺省构造函数的函数体为空。)就是无用的。编译器需要为该类合成出一个默认的构造函数。不过这个合成操作只有在构造函数真正需要被调用的时候才会发生。


//编译器对构造函数的扩张


//程序员定义的默认构造函数
Bar::Bar(){str=0;}
//扩张后的构造函数
Bar::Bar()
{
foo.Foo::Foo();
str=0;
}


②带有Default Constructor的  Base class
如果一个没有任何构造函数的类派生自一个带有“默认构造函数”的基类,那么这个派生类的默认构造函数会被视为有效的,并因此合成出来。




③带有一个Virutal Function的 class
下面良好总情况也需要合成default constructor
1、class声明(或继承)一个virtual function
2、class派生自一个继承串链,其中有一个或更多的virtual base class


下面两个扩张行动会在编译器期间发生:
1、一个virtual function table 会被编译器产生出来,内放置class 的virtual functions地址
2、在每一个class object中,一个额外的vptr会被编译器合成出来,内含相关的vtbl的地址。


④带有一个virtual base class 的class




5)c++ standard 把那些合成的默认构造函数称为implicit nontrivial default constructor。被合成的编译器只能满足编译器的需要,它之所以能完成任务是借着“member object或base class的default constructor”或是“为每一个object初始化其virtual function机制或是virtual base class机制”而完成。


以下两个认识都是错误的:
1、任何class如果没有定义default constructor,就会被合成出一个来。
2、编译器合成出来的default constructor会显示设定class内每一个data member的默认值。










6)有三种情况,会以一个object的内容作为另一个class object的初值。
1、对一个object做显示初始化操作   X xx=x;
2、当object作为参数交给某个函数时 foo(xx);
3、当函数传回一个class object时, return xx;




7)memberwise initialization和 bitwise copy仅仅是拷贝的两种方式:
memberwise initialization:当以一个对象初始化另一个对象的时候,会按对象的数据成员,逐个初始化。
bitwise copy:字节到字节的拷贝(一般调用memcpy函数,其效率比memberwise copy要高。)


以下4种情况,不展现bitwise copy sematics
①class内含一个member object,而后者的class声明一个copy constructor 
②class继承自一个基类而后者存在一个copy constructor.
③当class声明一个或多个virtual functions时
④当class派生自一个继承串链,其中有一个或多个virtual  base classes




8)拷贝构建:把实际参数直接构建在其应该的位置上,此位置视函数活动范围的不同,记录与程序堆栈中。


9)在编译器层面的优化,所有的return指令传回相同的“具名数值”(named value),因此编译器机子做优化,方法是以result参数取代named return value.NRV优化如今被视为标准C++编译器的一个义不容辞的操作。NRV优化的条件是优化函数的返回类型(一个类),该类需要具有拷贝构造函数,才能激活C++编译器的NRV优化。
关于NRV优化的一篇文章:http://www.cnblogs.com/autosar/archive/2011/10/09/2204181.html




10)对于 A class ob1=ob2;//该操作是初始化还是赋值,取决于ob1是否具有初值。


11)下面三个初始化操作在语意上是相等的:
①X xx0(1024);//xx0.X::X(1024);
②X xx1=X(1024);//1、将一个临时对象的object设置初值1024  2、调用拷贝构造函数赋值给xx1
③X xx2=(X)1024;
xx1 xx2 调用两次构造函数,一次是构造函数,另一次是拷贝构造函数




12) C++standard把copy constructor区分为trivial何nontrivial两种,只有nontrivial的实体才会被合成于程序之中。决定一个copy constructor是否为trivial的标准在于class是否展现出所谓的”bitwise copy semantics“


13)下列这些情况需要使用初始化列表:
①初始化一个 reference member
②处是一个const member
③当调用一个base class的constructor,而它拥有一组参数时(继承类)
④当调用一个member class 的constructor,而它拥有一组参数时(内含类对象)


例如
word::word: _name(0)
{
_cnt=0;
}
会被扩张成这样:
word::word{
_name.String::String(0);
_cnt=0;
}


14)初始化列表的初始化顺序由class中members声明顺序决定的,而不是initialization list中的排列顺序决定的。
简单的说,编译器会对initialization list一一处理并可能重新排序,以反映出members的声明顺序。它会安插一些代码到constructor体内,并置于任何explicit user code  之前

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值