C++中类的构造函数与复制构造函数

1 相关定义

1.1 构造函数

构造函数是类的特殊的成员函数,只要创建类类型的新对象,都要执行构造函数。构造函数的工作是保证每个对象的数据成员具有合适的初始值。构造函数的名字与类的名字相同,并且不能指定返回类型。像其他任何函数一样,它们可以没有形参,也可以定义多个形参。

1.2 复制构造函数

复制构造函数是一种特殊构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数。

2 两种初始化方式

C++支持两种初始化方式:直接初始化和复制初始化。

2.1 两种初始化方式的实现

复制初始化使用=符号,而直接初始化将初始化式放在圆括号中。

自定义一个名为MyClass的类。并且定义MyClass类的默认构造函数、自定义构造函数和复制构造函数。

class MyClass
{
public:
MyClass()
{
cout << "进入MyClass的默认构造函数" << endl;
}
MyClass(const char* pc)
{
cout << "进入MyClass自定义构造函数" << endl;
}
MyClass(const ClassTest& ct)
{
cout << "进入MyClass复制构造函数" << endl;
}
};

接下来使用直接初始化和复制初始化定义MyClass类的对象:

MyClass mc1(“myclass”);
MyClass mc2 = mc1;

运行后的效果如图所示

 

从上图可以看出,第1行代码调用了MyClass类的自定义构造函数,第2行代码调用了MyClass类的复制构造函数。

2.2 两种初始化方式的关系

对于MyClass类对象的定义,还有一种方式,如下所示

MyClass mc3 = “myclass”;

这种定义方式是采用了哪种初始化呢?《C++ Primer中文版第4版》P407页提到,以上这种定义方式,“编译器首先调用接受一个C风格字符串形参的构造函数,创建一个临时对象,然后,编译器使用复制构造函数将类的对象初始化为那个临时对象的副本”。也就是说,以上代码应该调用了MyClass类的两个构造函数,一个是自定义的参数为const char*的构造函数,一个是复制构造函数。然而,程序运行后的效果如图所示

 

此时,只调用了MyClass类的自定义函数,而没有调用复制构造函数。产生这个现象的原因,在网络上有朋友提到“主要原因在于编译器的优化,当复制构造函数是public时,编译器就会根据这个特性来对代码进行优化。当程序运行时,编译器发现复制构造函数是public,则说明程序允许对象之间的复制,此时就会通过直接调用自定义构造函数来初始化对象,而不再调用复制构造函数,完成优化”。这位朋友还提到,如果将复制构造函数改为private,此时如下代码

MyClass mc3 = “myclass”;

编译时就会报错。

但是,至少在VC++6.0及以上版本的编译器中,并不是这样的。在VC++6.0/VS2005/VS2008/VS2010/VS2015中进行测试,当将MyClass类的复制构造函数改为private后,上述代码编译时并不报错,而且都仅显示“调用了自定义构造函数”。这就说明,至少在VC++6.0/VS2005/VS2008/VS2010/VS2015的编译器当中,如下代码

MyClass mc3 = “myclass”;

并没有像《C++ Primer中文版第4版》中提到的那样,调用了两次构造函数,而是只调用了自定义的构造函数。可以说,在VC++6.0/VS2005/VS2008/VS2010/VS2015

MyClass mc1(“myclass”);

MyClass mc3 = “myclass”;

是等价的。

3 编译器优化

VC++6.0/VS2005/VS2008/VS2010/VS2015中进行测试时,确实发现了在“2.2”中提到的编译器优化问题。对于如下代码

MyClass mc4 = MyClass();

VC++6.0中进行测试时,运行结果显示编译器先调用MyClass类默认构造函数,之后调用复制构造函数;而在VS2005/VS2008/VS2010/VS2015中则只显示编译器调用了默认构造函数。并且如果将复制构造函数设置为private,编译器会报错,如下所示:

 error C2248: ClassTest::ClassTest: 无法访问 private 成员(在“ClassTest”类中声明)

这就说明,在VS2005/VS2008/VS2010/VS2015中,编译器进行了优化,当发现复制构造函数是public时,直接调用默认构造函数。而当复制构造函数是private时,就会报错。

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页