17、C++ Primer 4th 笔记,构造函数

简介: 1、构造函数初始化式只在构造函数的定义中而不是声明中指定。 2、从概念上讲,可以认为构造函数分两个阶段执行:(1)初始化阶段;(2) 普通的计算阶段。计算阶段由构造函数函数体中的所有语句组成。不管成员是否在构造函数初始化列表中显式初始化,类类型的数据成员总是在初始化阶段初始化。

1、构造函数初始化式只在构造函数的定义中而不是声明中指定。

2从概念上讲,可以认为构造函数分两个阶段执行:(1)初始化阶段;(2

普通的计算阶段。计算阶段由构造函数函数体中的所有语句组成。不管成员是否在构造函数初始化列表中显式初始化,类类型的数据成员总是在初始化阶段初始化。初始化发生在计算阶段开始之前。

3、使用构造函数初始化列表的版本初始化数据成员,没有定义初始化列表的构造函数版本在构造函数函数体中对数据成员赋值。

4、没有默认构造函数的类类型的成员,以及 const 或引用类型的成员,不管是哪种类型,都必须在构造函数初始化列表中进行初始化。

5、内置类型的成员不进行隐式初始化,对非类类型的数据成员进行赋值或使用初始化式在结果和性能上都是等价的。

6、成员被初始化的次序就是定义成员的次序。

7、按照与成员声明一致的次序编写构造函数初始化列表是个好主意。此外,尽可能避免使用成员来初始化其他成员。

8、初始化式可以是任意表达式。

9、我们更喜欢使用默认实参,因为它减少代码重复。

示例

#include "iostream"

using namespace std;

class Sales_item {
public:
	//default argument for book is the empty string
	Sales_item(const std::string &book = ""):
	  isbn(book), units_sold(0), revenue(0.0) { }
    Sales_item(std::istream &is);
	  // as before
private:
	string isbn;
	int units_sold;
	int revenue;
};

int main()
{
	Sales_item empty;
	Sales_item Primer_3rd_Ed("0-201-82470-1");
	return 1;
}

10、只有当一个类没有定义构造函数时,编译器才会自动生成一个默认构造函数。通常,在默认构造函数中给成员提供的初始值应该指出该对象是“空”的。

11、如何使用默认构造函数?

示例

Sales_item myobj();// oops! declares a function, not an object
//the following are right.
Sales_item myobj; //defines a class object ...
Sales_item myobj = Sales_item() //ok,create an unnamed, empty Sales_itemand use to initialize myobj

12、隐式类型转换

示例

class Salse_item
{
publi:
	Salse_item(const std::string &book = ""):isbn(book)...{}
	Salse_item(std::iostream &is);
	//explicit Salse_item(std::iostream &is);

	...
	bool same_isbn(Salse_item &si)
	{
	...
	}
};

int main()
{
	Salse_item item;
	string null_book = "12345";
	item.same_isbn(null_book); //会发生自动转换,把string类型转换成Salse_item型。
	item.same_isbn(cin);  ////会发生自动转换,把cin流类型转换成Salse_item型。
	//item.same_isbn(Salse_item(null_book)); //显式的进行转换
}

如上例中所示,我们构造了一个测试完成后被丢弃的对象,这个行为几乎是一个错误。

1)抑制由转换构造函数定义的隐式转换

声明为explicit,来停止隐式转换的上下文中使用构造函数。

2)如果真的需要转换,则显式的进行。

    通常,除非有明显的理由想要定义隐式转换,否则,单形参构造函数应该为 explicit

参考

[1] http://blog.163.com/zhoumhan_0351/blog/static/3995422720100250413207/

[2] http://blog.163.com/zhoumhan_0351/blog/static/39954227201032845132592/

[3] http://blog.163.com/zhoumhan_0351/blog/static/399542272010318112048522/

[4] http://blog.163.com/zhoumhan_0351/blog/static/39954227201032092854732/

[5] http://blog.163.com/zhoumhan_0351/blog/static/3995422720100284731826/

目录
相关文章
|
3月前
|
编译器 C++
《Effective C++ 改善程序与设计的55个具体做法》 第一章 笔记
《Effective C++ 改善程序与设计的55个具体做法》 第一章 笔记
|
27天前
|
C++ 容器
【C/C++笔记】迭代器
【C/C++笔记】迭代器
13 1
|
1月前
|
编译器 C++
C++的基类和派生类构造函数
基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。 在设计派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数完成,但是大部分基类都有 private 属性的成员变量,它们在派生类中无法访问,更不能使用派生类的构造函数来初始化。 这种矛盾在C++继承中是普遍存在的,解决这个问题的思路是:在派生类的构造函数中调用基类的构造函数。 下面的例子展示了如何在派生类的构造函数中调用基类的构造函数:
23 1
|
27天前
|
存储 安全 程序员
【C/C++笔记】迭代器范围
【C/C++笔记】迭代器范围
50 0
|
2月前
|
C++ Windows
FFmpeg开发笔记(三十九)给Visual Studio的C++工程集成FFmpeg
在Windows上使用Visual Studio 2022进行FFmpeg和SDL2集成开发,首先安装FFmpeg至E:\msys64\usr\local\ffmpeg,然后新建C++控制台项目。在项目属性中,添加FFmpeg和SDL2的头文件及库文件目录。接着配置链接器的附加依赖项,包括多个FFmpeg及SDL2的lib文件。在代码中引入FFmpeg的`av_log`函数输出"Hello World",编译并运行,若看到"Hello World",即表示集成成功。详细步骤可参考《FFmpeg开发实战:从零基础到短视频上线》。
66 0
FFmpeg开发笔记(三十九)给Visual Studio的C++工程集成FFmpeg
|
3月前
|
安全 编译器 C++
C++一分钟之-构造函数与析构函数
【6月更文挑战第20天】C++中的构造函数初始化对象,析构函数负责资源清理。构造函数有默认、参数化和拷贝形式,需注意异常安全和成员初始化。析构确保资源释放,避免内存泄漏,要防止重复析构。示例代码展示了不同构造函数和析构函数的调用情况。掌握构造和析构是有效管理对象生命周期和资源的关键。
36 2
|
2月前
|
编译器 C++
【C++】详解构造函数
【C++】详解构造函数
|
3月前
|
存储 编译器 C++
【C++】类和对象④(再谈构造函数:初始化列表,隐式类型转换,缺省值
C++中的隐式类型转换在变量赋值和函数调用中常见,如`double`转`int`。取引用时,须用`const`以防修改临时变量,如`const int& b = a;`。类可以有隐式单参构造,使`A aa2 = 1;`合法,但`explicit`关键字可阻止这种转换。C++11起,成员变量可设默认值,如`int _b1 = 1;`。博客探讨构造函数、初始化列表及编译器优化,关注更多C++特性。
|
3月前
|
存储 编译器 C语言
【C++】类和对象②(类的默认成员函数:构造函数 | 析构函数)
C++类的六大默认成员函数包括构造函数、析构函数、拷贝构造、赋值运算符、取地址重载及const取址。构造函数用于对象初始化,无返回值,名称与类名相同,可重载。若未定义,编译器提供默认无参构造。析构函数负责对象销毁,名字前加`~`,无参数无返回,自动调用以释放资源。一个类只有一个析构函数。两者确保对象生命周期中正确初始化和清理。
|
3月前
|
SQL 人工智能 算法
技术心得记录:模板函数函数模板FunctionTemplate(C++Primer
技术心得记录:模板函数函数模板FunctionTemplate(C++Primer