读书人

关于直接初始化和复制初始化的疑惑,该

发布时间: 2012-02-11 09:51:35 作者: rapoo

关于直接初始化和复制初始化的疑惑
#include <iostream>

using std::cout;
using std::endl;

class test
{
public:
test(int i):ival(i){cout < < "调用了以一个int为形参的构造函数 " < <endl;}
test(const test& t):ival(t.ival){cout < < "调用了复制构造函数 " < <endl;}
private:
int ival;
};


int main(int argc,char * argv[])
{
test t1=1;
return 0;
}
这里用test t1=1;的方法来创建t1,因该是复制初始化吧?那么,初始化的过程应该是先用test(int i)创建一个临时对象,再用复制构造函数test(const test& t)将临时对象复制到正在创建的对象t1.这样的话,输出因该是:
调用了以一个int为形参的构造函数
调用了复制构造函数
可事实上只输出了一行字:
调用了以一个int为形参的构造函数
并没用调用复制构造函数。另外,将复制构造函数test(const test& t)放到private区段,此程序仍未出现任何错误,这也说明没用调用过复制构造函数test(const test& t)。这是什么原因呢?
继续测试,将main函数改为
int main(int argc,char * argv[])
{
test t2=test(1);
return 0;
}
这下总该调用复制构造函数了吧?
可事实上输出仍只有一行字:
调用了以一个int为形参的构造函数
然而,当我把复制构造函数test(const test& t)放到private区段时,编译时却会出错:
error C2248: “test::test”: 无法访问 private 成员(在“test”类中声明)
这么说来,还是要调用复制构造函数test(const test& t)呀,可是为什么没有显示“调用了复制构造函数”呢?

[解决办法]
你的理解是有问题哟,如果你不自己声明,c++会为每个类生成一个默认的
构造函数,一个拷贝构造函数,一个赋值操作符函数, 针对你的程序:
1. test t1 = 1; //这条语是直接调用test(int i)进行初始化的,并没有生成临时变量,
也没有调用test(const test& t) 拷贝构造函数。
2. test t2 = test(1);// 这条语句同上面的调用过程一样

看下面的示例
#include <iostream>

using std::cout;
using std::endl;

class test
{
public:
test(int i):ival(i){cout < < "调用了以一个int为形参的构造函数 " < <endl;}
test(const test& t):ival(t.ival){cout < < "调用了复制构造函数 " < <endl;}

void operator = (const test& t)// 定义一个赋值操作符函数
{
ival = t.ival;
cout < < "调用了赋值操作符=函数 " < <endl;
}
private:
int ival;
};


int main(int argc,char * argv[])
{
test t1 = 1; //仅调用ival(1)

t1 = 2; //调用ival(2)产生临时对象后
//在调用operator = 函数完成赋值操作


test t2(t1); //调用test(int i)对t2进行初始化

return 0;

}


[解决办法]
1. test t1 = 1;
2. test t2 = test(1);
还有你写的两个语句都是初始化的过程, 是不会生成临时对象的,就是即时生成临时变量,也是赋值操作符的问题,和拷贝构造函数没关系。
这也就是为生么类对象的初始化比赋值效率高的原因,如
test t1;
t1 = 1;
//这样写会产生临时对象,它的效率就比 test t1 = 1的;效率低一些

[解决办法]
to a013231():
对于test t2 = test(1); 语句
因为是初始化,根据c++语法编译器解析时确定它的确应该
调用复制构造函数test(const test& t),所以当,test(const test& t) 拷贝构造函数为private时会编译出错,但是,编译器在代码生成时会做一定的优化,不同的编译器这种优化程度也可能不同,如是对于test t2 = test(1);初始化过程所需要产生不必要临时对象的过程被优化掉了,而其实际调用过程同test t1 = 1;初始化的调用是一样的,看以下的反汇编代码:

test t1 = test(1);
//可以看出这一段代码和下一段test t3 = 1;的反汇编代码一样
//而其调用过程也是一样的
0041182E push 1
00411830 lea ecx,[t1]
00411833 call test::test (4111C7h) //调用test(int i)
test t3 = 1;
00411838 push 1
0041183A lea ecx,[t3]
0041183D call test::test (4111C7h) //调用test(int i)
t1 = 2; //调用ival(2)产生临时对象后
00411842 push 2
00411844 lea ecx,[ebp-0ECh]
0041184A call test::test (4111C7h) //调用test(int i)
0041184F lea eax,[ebp-0ECh]


00411855 push eax
00411856 lea ecx,[t1]
00411859 call test::operator= (4111EAh) //在调用operator = 函数完成赋值操作

test t2(t1); //调用test(int i)对t2进行初始化
0041185E lea eax,[t1]
00411861 push eax
00411862 lea ecx,[t2]
00411865 call test::test (41125Dh) //调用test(const test& t)

读书人网 >C++

热点推荐