C++标准ISO-IEC-14882-2003:第12章:类的特殊成员函数-第1节:构造函数

12. 特殊成员函数 【按:以下简称特殊函数或这些函数;如没有特别说明,对象是指类实例化的对象, 最外层的对象是指最继承子对象】

特殊成员函数包括默认构造函数、拷贝构造函数、拷贝赋值操作符和析构函数。除了 12.1 中的情况,当程序不显式地声明这些函数时,编译器会隐式声明它们;如果使用了它们,编译器还会隐式地定义这些函数,如 12.1 12.4 12.8 所示。不能够在程序中定义隐式声明的特殊函数。 【按:要么不自定义,要自定义就得自己声明】 程序中可以显式地使用隐式声明的特殊函数。

【例:程序中可以显式调用这些函数、对其取地址、或是构造一个指向这些函数的指针。

struct A {};   // 隐式地定义了 A::operator= 函数

struct B: A

{

       B& operator = (const B&);

};

B& B::operator = (const B& s)

{

       this->A::operator=(s);  // 合法

       return *this;

}

】【注:特殊成员函数影响对象的创建、拷贝、销毁以及值的类型转化的方式。通常这些函数是被隐式地调用的。】

特殊成员函数遵循普通成员函数的访问权限控制。【例如:将一个类的构造函数声明为 protected ,就能保证只有派生类或友元可以使用这个构造函数进而实例化该类的对象。】

 

12.1 构造函数

1.         构造函数没有名字。声明或定义构造函数的时候需要一种特殊的语法:函数说明符(可选) + 类名 + 参数列表。在这个语法中,括住类名的圆括号(可选)会被忽略。

【按:函数说明符一共有3 个:inline, virtual, explicit ,其中virtual 在这里不允许使用】

2.         构造函数是用来初始化该类的对象的。因为没有名字,所以在名字查找 过程中构造函数永远不会被涉及到;然而使用函数式的显式类型转换 【按:即类似C 语言的强制类型转换语法】 却会导致构造函数被调用从而进行对象初始化。【注:对象初始化参见 12.6 节】

3.         命名一个类的 typedef-name 也是个类名,但是这个 typedef-name 却不能用作构造函数的标识符。

4.         构造函数不能为 virtual static 。构造函数可以被 const volatile const volatile 的对象调用。构造函数不能声明为 const volatile const volatile 类型的成员,因为 const volatile 的语义对于一个正在构建的对象来说是不适用的,这些语义只有在最外层的对象构建完毕之后才生效。

5.         X 的默认构造函数是 X 的不带任何参数的构造函数。如果用户没有为 X 声明任何构造函数,默认构造函数就会被隐式地声明。隐式声明的默认构造函数的属性是 inline public 的。当隐式声明的默认构造函数满足以下条件时,它被称为是 trivial 的:

       【按: trivial 是无关痛痒、可忽略的意思】

a)         类没有虚函数,没有虚基类

b)        所有直接基类都具有 trivial 的构造函数

c)        对于所有非静态数据成员来说,如果它是类(或对象数组),那每个这样的数据成员都得有 trivial 的构造函数

6.         否则,构造函数就是非 trivial 的。

7.         当用隐式声明的默认构造函数来创建一个对象的时候,它会被隐式地定义。该构造函数执行的初始化操作与用户写的空默认构造函数(初始化列表为空,函数体为空)完全相同。如果拿用户写的这个构造函数替换掉隐式定义的默认构造函数之后发现是非法的,那么替换之前的程序也必定是非法的。在隐式定义的默认构造函数被隐式定义之前,该类的所有基类的默认构造函数、该类的所有非静态数据成员的构造函数 都必须已经定义好。【注:隐式声明的默认构造函数还会有一个异常说明。】默认构造函数被用来:

a)         创建没有初值的静态或自动存储类型对象;

b)        创建省略 new-initializer new 表达式创建的动态存储类型对象;

c)        显式类型转换时调用。

8.         如果默认构造函数被使用了,但是该函数却由于权限的缘故而无法访问,那么程序就是非法的。

9.         【注: 12.6.2 描述了基类构造函数和非静态数据成员的构造函数 的调用顺序以及调用这些构造函数时参数该如何传递】

10.     X 的拷贝构造函数是个参数为 X& const X& 的构造函数

11.     union 的成员如果是个类,那么这个类的构造函数必须是 trivial

12.     构造函数永远都不能有返回类型,甚至连返回 void 类型都不允许。在构造函数体中,可以用 return 语句,但不能返回任何值。不要试图去取构造函数的地址。

13.     函数式的显式类型转换会创建一个该类的(临时)对象。【注:语法看起来有点儿像构造函数的显式调用】这样创建的对象是没有名字的。【注:显式的构造函数调用永远不会生成左值】

14.     【注:上述第 13 条的语法如果在构造函数中使用,那么在某些清况下它有特殊的语义: 12.6.2 12.7 【按:用在初始化列表中,用来初始化基类子对象】

15.     const 对象的创建过程中,如果该对象或子对象的值被作为一个左值使用,而该左值却又不是通过 this 指针获得的(比如直接使用该对象的名字),那么这样获得的值是未定义的。【例:

struct C;

void no_opt(C*);

struct C

{

        int c;

        C() : c(0) {no_opt(this);}

};

 

const C cobj;

 

void no_opt(C* cptr)

{

        int i = cobj.c * 100;              // 该函数在 cobj 的构造函数中被调用,这里是通过 cobj 而不是 this 获取 c 的值(是个左值,然后自动转化为右值),所以该值是未定义的

        cptr->c = 1;

        cout << i << endl;

        cout << cobj.c * 100 << endl;

};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值