《Effective C++ 》学习笔记——条款05
2014-11-03 21:38
183 查看
***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************
二、Constructors,Destructors and Assignment Operators
从第一章认识了C++后,开始进入第二章节的学习了,这一章主要讲述的就是 构造、析构及赋值运算。对于每一个类,都会有 一个或多个 构造函数,一个析构函数 和 一个 copy assignment 运算符。这些东西对于一个C++程序员,是最基本的谋生工具,这些函数的行为将会对你的程序造成巨大的影响,因此,这一章提供良好的引导,让你将这些函数良好的结合在一起,形成classes的支柱。
Rule 05:Know what functions C++ silently writes and calls
规则05:了解C++默默编写并调用哪些程序
1. 关于一个空类——empty class
首先要明白,如果我们写了一个空类,当C++处理它时,会产生什么或者调用什么函数呢?
比如,我们写一个类:
class Empty {};
当C++处理它时,虽然你什么都没有写,但是里面相当于这样的:
class Empty{
public:
Empty() {...}<span style="white-space:pre"> </span>// default 构造函数
Empty( const Empty& rhs ) {...}<span style="white-space:pre"> </span>// copy 构造函数
~Empty() {...}<span style="white-space:pre"> </span>// 析构函数(是否为virtual,稍后论证)
Empty& operator=( const Empty& rhs) {...}<span style="white-space:pre"> </span>// copy assignment操作符
};
没错,就是这样,即使你什么都没写,C++会自动给这个空类,填上这些东西。当然这里面有些东西是可以通过我们来覆盖,或者有些东西会根据类成员内容而不产生,这些后面都会讲述到。
我们要知道,对于大多数的类,这几个东西是必备的:default构造函数,copy构造函数,析构函数,copy assignment操作符,而且这些函数都是 public 且 inline的。
还要明确一点,虽然类中“添加”了这么多东西,但并不是一调用对象就会使用这个函数,比如:
当新建一个Empty类的对象
Empty e1;
这时,default构造函数 和 析构函数 会被编译器产出。
而这样时:
Empty e2(e1); // copy构造函数被产出
e2 = e1; // copy assignment操作符 被产出
2. 类中这些东西的作用?
<1> 对于 default构造函数 和 析构函数
主要是给编译器一个地方用来放置“幕后”代码,比如,调用 base classes 和 non-static 成员变量的构造函数和析构函数。(注意:编译器产出的析构函数是 non-virtual 的, 除非这个类的基类自身声明有virtual 析构函数)
<2> 对于 copy构造函数 和 copy assignment 操作符
编译器创建的版本只是单纯的将来源对象的每一个non-static 成员变量拷贝到目标对象。
3. copy 构造函数 and copy assignment操作符
对于一个 NamedObject template 类,它允许你将一个个名称和类型为T的对象产生关联
template<typename> T
class NamedObject {
public:
NamedObject( const char* name, const T& value);
NamedObject( const std::string& name, const T& value);
....
private:
std::string nameValue;
T objectValue;
};☆PS:由于这个类中声明了一个构造函数,所以编译器不会再为它创建 default构造函数。☆
可以看到,上面的类中并没有声明 copy 构造函数,也没有声明 copy assignment操作符,所以如果它们被调用,编译器就会为它创造这些函数。
copy函数调用:
NamedObject<int> no1("Smallest Prime Number",2);
NamedObject<int> no2(no1); // 调用copy 构造函数
下面看编译器对这个函数如何操作,
首先,编译器生成的构造函数 必须 以no1的两个成员变量 nameValue 和 objectValue为初值 来设定 no2 的两个成员变量。
在两者之中,nameValue类型是 string 并不是 内置类型,而标准的string有copy构造函数,所以,no2.nameValue初始化是调用 string 的copy构造函数,并以no1.nameValue为实参。
而另一个成员的类型是内置类型 int ,所以no2.objectValue会以“拷贝no1.objectValue内的每一个bits”来进行初始化。
对于copy assignment操作符,在满足下两个条件下,会同copy构造函数一致。
① 生成的代码合法
②有适当的机会证明它有意义
否则 编译器 会拒绝为 class 生出 operator =
4.接下来,继续看个例子:
template<class T>
class NamedObject {
public:
NamedObject( std::string& name, const T& value );
...
pirvate:'
std::string& nameValue;
const T objectValue;
};
看到,nameValue成了 引用类型, objectValue成了 const,
所以,如果这样定以后,执行下列操作:
std::string newDog("Persephone");
std::string oldDog("Satch");
NamedObject<int> p(newDog,2);
NamedObject<int> s(oldDog,36);
p=s;
最重要的是,执行 p=s 这一行时会发生什么?
p.nameValue 指向 s.nameValue的那个string吗?
当然不行!
C++ 不允许“让reference改指向不同对象”
所以,这种情况下,如何解决呢?
C++的响应是——拒绝编译那一行赋值动作。
其实,下列三种情况,C++会“无能为力”
<1> 打算在一个“内涵reference成员”的 class 内支持 赋值操作,这样情况,必须自己定义copy assignment操作符
<2> 面对“内含const成员”的classes,编译器的反应也一样,因为更改const成员是不合法的。
<3> 再有就是 如果某个 base classes 将copy assignment操作符声明为 private,编译器将拒绝为其 derived classes 生成 copy assignment 操作符。
5.Please Remember
编译器可以暗自为 class 创建 default构造函数、copy构造函数、copy assignment操作符 以及析构函数。
***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************
二、Constructors,Destructors and Assignment Operators
从第一章认识了C++后,开始进入第二章节的学习了,这一章主要讲述的就是 构造、析构及赋值运算。对于每一个类,都会有 一个或多个 构造函数,一个析构函数 和 一个 copy assignment 运算符。这些东西对于一个C++程序员,是最基本的谋生工具,这些函数的行为将会对你的程序造成巨大的影响,因此,这一章提供良好的引导,让你将这些函数良好的结合在一起,形成classes的支柱。
Rule 05:Know what functions C++ silently writes and calls
规则05:了解C++默默编写并调用哪些程序
1. 关于一个空类——empty class
首先要明白,如果我们写了一个空类,当C++处理它时,会产生什么或者调用什么函数呢?
比如,我们写一个类:
class Empty {};
当C++处理它时,虽然你什么都没有写,但是里面相当于这样的:
class Empty{
public:
Empty() {...}<span style="white-space:pre"> </span>// default 构造函数
Empty( const Empty& rhs ) {...}<span style="white-space:pre"> </span>// copy 构造函数
~Empty() {...}<span style="white-space:pre"> </span>// 析构函数(是否为virtual,稍后论证)
Empty& operator=( const Empty& rhs) {...}<span style="white-space:pre"> </span>// copy assignment操作符
};
没错,就是这样,即使你什么都没写,C++会自动给这个空类,填上这些东西。当然这里面有些东西是可以通过我们来覆盖,或者有些东西会根据类成员内容而不产生,这些后面都会讲述到。
我们要知道,对于大多数的类,这几个东西是必备的:default构造函数,copy构造函数,析构函数,copy assignment操作符,而且这些函数都是 public 且 inline的。
还要明确一点,虽然类中“添加”了这么多东西,但并不是一调用对象就会使用这个函数,比如:
当新建一个Empty类的对象
Empty e1;
这时,default构造函数 和 析构函数 会被编译器产出。
而这样时:
Empty e2(e1); // copy构造函数被产出
e2 = e1; // copy assignment操作符 被产出
2. 类中这些东西的作用?
<1> 对于 default构造函数 和 析构函数
主要是给编译器一个地方用来放置“幕后”代码,比如,调用 base classes 和 non-static 成员变量的构造函数和析构函数。(注意:编译器产出的析构函数是 non-virtual 的, 除非这个类的基类自身声明有virtual 析构函数)
<2> 对于 copy构造函数 和 copy assignment 操作符
编译器创建的版本只是单纯的将来源对象的每一个non-static 成员变量拷贝到目标对象。
3. copy 构造函数 and copy assignment操作符
对于一个 NamedObject template 类,它允许你将一个个名称和类型为T的对象产生关联
template<typename> T
class NamedObject {
public:
NamedObject( const char* name, const T& value);
NamedObject( const std::string& name, const T& value);
....
private:
std::string nameValue;
T objectValue;
};☆PS:由于这个类中声明了一个构造函数,所以编译器不会再为它创建 default构造函数。☆
可以看到,上面的类中并没有声明 copy 构造函数,也没有声明 copy assignment操作符,所以如果它们被调用,编译器就会为它创造这些函数。
copy函数调用:
NamedObject<int> no1("Smallest Prime Number",2);
NamedObject<int> no2(no1); // 调用copy 构造函数
下面看编译器对这个函数如何操作,
首先,编译器生成的构造函数 必须 以no1的两个成员变量 nameValue 和 objectValue为初值 来设定 no2 的两个成员变量。
在两者之中,nameValue类型是 string 并不是 内置类型,而标准的string有copy构造函数,所以,no2.nameValue初始化是调用 string 的copy构造函数,并以no1.nameValue为实参。
而另一个成员的类型是内置类型 int ,所以no2.objectValue会以“拷贝no1.objectValue内的每一个bits”来进行初始化。
对于copy assignment操作符,在满足下两个条件下,会同copy构造函数一致。
① 生成的代码合法
②有适当的机会证明它有意义
否则 编译器 会拒绝为 class 生出 operator =
4.接下来,继续看个例子:
template<class T>
class NamedObject {
public:
NamedObject( std::string& name, const T& value );
...
pirvate:'
std::string& nameValue;
const T objectValue;
};
看到,nameValue成了 引用类型, objectValue成了 const,
所以,如果这样定以后,执行下列操作:
std::string newDog("Persephone");
std::string oldDog("Satch");
NamedObject<int> p(newDog,2);
NamedObject<int> s(oldDog,36);
p=s;
最重要的是,执行 p=s 这一行时会发生什么?
p.nameValue 指向 s.nameValue的那个string吗?
当然不行!
C++ 不允许“让reference改指向不同对象”
所以,这种情况下,如何解决呢?
C++的响应是——拒绝编译那一行赋值动作。
其实,下列三种情况,C++会“无能为力”
<1> 打算在一个“内涵reference成员”的 class 内支持 赋值操作,这样情况,必须自己定义copy assignment操作符
<2> 面对“内含const成员”的classes,编译器的反应也一样,因为更改const成员是不合法的。
<3> 再有就是 如果某个 base classes 将copy assignment操作符声明为 private,编译器将拒绝为其 derived classes 生成 copy assignment 操作符。
5.Please Remember
编译器可以暗自为 class 创建 default构造函数、copy构造函数、copy assignment操作符 以及析构函数。
***************************************转载请注明出处:http://blog.csdn.net/lttree********************************************
相关文章推荐
- 《Effective C++》学习笔记条款05了解C++默默编写并调用哪些函数
- 《Effective C++》学习笔记——条款18
- 《Effective C++》学习笔记——条款22
- 《Effective C++》学习笔记——条款24
- 《Effective C++》学习笔记条款06 若不想使用编译器自动生成的函数,就该明确拒绝
- 《Effective C++》学习笔记条款10 令operator= 返回一个reference to *this
- 《Effective C++ 》学习笔记——条款03
- [Effective C++]条款05 了解C++默默编写并调用哪些函数
- effective c++ 条款05、06(编译器自动生成函数)整理
- 《Effective C++》学习笔记条款07 为多态基类声明virtual析构函数
- 《Effective C++》学习笔记条款11 在operator =中处理“自我赋值”
- 《Effective C++》学习笔记条款12 复制对象时勿忘其每一个成员
- Effective C++:条款05
- 《Effective C++》学习笔记——条款29
- Effective C++ 条款05 什么时候不应该使用编译器默认提供的函数
- 《Effective C++》学习笔记条款25 考虑写出一个不抛异常的swap函数
- 《Effective C++》学习笔记条款29 为“异常安全”而努力是值得的
- 《Effective C++ 3》05 实现 条款:26-31
- 《Effective C++》学习笔记——条款40
- 《Effective C++》学习笔记——条款31