拷贝构造函数

来源:互联网 发布:php短信验证码生成 编辑:程序博客网 时间:2024/06/04 00:20


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

class X {
public:
    //X(){};
    X(const X& a){std::cout<<"haha..."<<std::endl;};
    ~X(){std::cout<<"~X()..."<<std::endl;};
};

编译:error C2512: “X”: 没有合适的默认构造函数可用


如果在类中根本没有构造函数,编译器将自动地创建一个缺省的构造函数。不过在这种情况下,这个构造函数什么也不做。然而,如果我们加了一个拷贝构造函数,我们就告诉了编译器我们将自己处理构造函数的创建,编译
器将不再为我们创建缺省的构造函数。并且除非我们显式地创建一个缺省的构造函数,否则,编译器会指示出错。


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


//: C11:HowMany2.cpp

// The copy-constructor

#include <fstream>

#include <string>

using namespace std;

ofstream out("HowMany2.out");

class HowMany2 {

string name; // Object identifier

static int objectCount;

public:

HowMany2(const string& id = "") : name(id) {

++objectCount;

print("HowMany2()");

}

~HowMany2() {

--objectCount;

print("~HowMany2()");

}

// The copy-constructor:

HowMany2(const HowMany2& h) : name(h.name) {

name += " copy";

++objectCount;

print("HowMany2(const HowMany2&)");

}

void print(const string& msg = "") const {

if(msg.size() != 0)

out << msg << endl;

out << '/t' << name << ": "

<< "objectCount = "

<< objectCount << endl;

}

};

int HowMany2::objectCount = 0;

// Pass and return BY VALUE:

HowMany2 f(HowMany2 x) {

x.print("x argument inside f()");

out << "Returning from f()" << endl;

return x;

}

int main() {

HowMany2 h("h");

out << "Entering f()" << endl;

 

HowMany2 h2 = f(h);

//h值传递,先调用拷贝构造函数

// 在退出函数前,需先将x拷贝到外面的返回值处,因此先调用拷贝构造函数,从h copy拷贝,最后才调用x的析构函数

 

 

 

h2.print("h2 after call to f()");

 

out << "Call f(), noreturn value" << endl;

f(h);

// 首先拷贝构造,尽管忽略了返回值,但在调用之前就将返回值的地址入栈了,

因此编译器需要创建一个临时对象,在退出之前,将h copy复制到临时对象中,

最后释放局部对象h copy,函数返回后,语句执行完毕,临时对象无用,析构释放

 

 

 

 

out << "After call to f()" << endl;

按照构造的相反顺序析构

} ///:~

 

1) HowMany2()

2)h: objectCount = 1

3) Entering f()

4) HowMany2(const HowMany2&)

5)h copy: objectCount = 2

6) x argument inside f()

7)h copy: objectCount = 2

8) Returning from f()

9) HowMany2(const HowMany2&)

10)h copy copy: objectCount = 3

11) ~HowMany2()

12)h copy: objectCount = 2

13) h2 after call to f()

14)h copy copy: objectCount = 2

15) Call f(), no return value

16) HowMany2(const HowMany2&)

17)h copy: objectCount = 3

18) x argument inside f()

19)h copy: objectCount = 3

20) Returning from f()

21) HowMany2(const HowMany2&)

22)h copy copy: objectCount = 4

23) ~HowMany2()

24)h copy: objectCount = 3

25) ~HowMany2()

26)h copy copy: objectCount = 2

27) After call to f()

28) ~HowMany2()

29)h copy copy: objectCount = 1

30) ~HowMany2()

31)h: objectCount = 0

 

此间要注意临时变量的创建和销毁。

临时对象
1 5行开始调用f ( h ),这次调用忽略了返回值。在1 6行可以看到恰好在参数传入之前,拷贝
构造函数被调用。和前面一样, 2 1行显示了为返回值而调用拷贝构造函数。但是,拷贝构造函
数必须有一个作为它的目的地( t h i s指针)的工作地址。对象返回到哪里?
每当编译器需要正确地计算一个表达式时,编译器可以创建一个临时对象。在这种情况下,
编译器创建一个我们甚至看不见的对象作为函数f( )忽略了的返回值的目的地地址。这个临时
对象的生存期应尽可能地短,这样,空间就不会被这些等待被销毁且占珍贵资源的临时对象搞
乱。在一些情况下,临时对象可能立即传递给另外的函数。但在现在这种情况下,在函数调用
之后,不需要临时对象,所以一旦函数调用以对内部对象调用析构函数( 2 3和2 4行)的方式结
束,临时对象就被销毁(2 5和2 6行)。在2 8 - 3 1行,对象h 2被销毁了,接着对象h被销毁。对象记数非常正确地回到了0。


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

默认拷贝函数的使

只有在需要值传递时才需要拷贝构造函数。为了防止编译器为你自动生成拷贝构造函数导致问题,可以声明一个私有的拷贝构造函数,若成员函数或者friend函数不进行值传递的话,甚至不需要定义拷贝构造函数。这样编译器不会为你自动生成,但同时你自己定义的为私有函数,编译器不能调用,因此会告警

//: C11:NoCopyConstruction.cpp

// Preventing copy-construction

class NoCC {

int i;

NoCC(const NoCC&); // No definition

public:

NoCC(int ii = 0) : i(ii) {}

};

void f(NoCC);

int main() {

NoCC n;

//! f(n); // Error: copy-constructor called

//! NoCC n2 = n; // Error: c-c called

//! NoCC n3(n); // Error: c-c called

} ///:~

 


原创粉丝点击