在
c语言中,函数中按值传递且传递的内容都很小,一般都是采用
bit复制方式,但是到了
C++中,传递的有可能是对象,这样传递的内容就会大大增加,默认也是采用
bit复制方式
(bit-copy),但是这样就会导致大量的数据被复制,而且更关键的是构造函数不会被调用。如:
- #include <fstream>
-
#include <iostream>
-
using namespace std;
-
-
class HowMany
-
{
-
static int objectCount;
-
int count;
-
public:
-
HowMany(){
-
count=10;
-
objectCount++;
-
cout<<"construction is called here!"<<endl;
-
}
-
static void print(const string& msg=""){
-
if(msg.size()!=0) cout<<msg<<":";
-
cout<<"objectCount = "<<objectCount<<endl;
-
}
-
void Increase(){
-
cout<<"before:"<<count;
-
count++;
-
cout<<"after "<<count<<endl;
-
}
-
void Decrease(){
-
cout<<"before:"<<count;
-
count--;
-
cout<<"after "<<count<<endl;
-
}
-
~HowMany(){
-
objectCount--;
-
cout<<"count:"<<count<<endl;
-
print("~HowMany()");
-
}
-
};
-
int HowMany::objectCount =0;
-
HowMany f(HowMany x)
-
{
-
//行参被复制传递一次
-
x.print("function f is called here");
-
return x;
-
}
-
-
int main()
-
{
-
HowMany *h=new HowMany;
-
HowMany::print("after construction of h");
-
HowMany h2(*h);
-
h->Increase();
-
h2.Decrease();
-
HowMany::print("after call to f()");
-
delete h;
-
return 0;
-
}
编译运行上面的代码:
- construction is called
-
-
after construction of h:objectCount = 1
-
-
before:10after 11
-
-
before:10after 9
-
-
after call to f():objectCount = 1
-
-
count:11
-
-
~HowMany():objectCount = 0
-
-
count:9
-
-
~HowMany():objectCount = -1
可以看出在调用初始化函数,确实只调用一次,这样h2就没有调用该函数了,一般来讲,如果没有指针的情况下,是可以的,如果含有指针的形式,bit复制就会导致两个对象同时指向一个对象了,如下面的示例:
编译上面的代码,就会出现下面的结果:
- construction is called
-
-
after construction of h:objectCount = 1
-
-
before:0after 1
-
-
before:1after 0
-
-
after call to f():objectCount = 1
-
-
count:0
-
-
~HowMany():objectCount = 0
这样两个对象同时指向同一个变量,不包含指针的情况下,不实现copy-constructor是可以的。如果实现copy-constructor,其实也很简单,但是参数的传递是个问题:对象不能通过值传递给构造函数(copy-constructor是构造函数),因为定义的就是处理按值传递,又按值传递,这样就错误了,同样不能进行按指针传递,因为你正在从一个已存在的对象中创建一个新对象,这里只能是引用了,而且只读(const),所以定义为下面的形式:
- HowMany(const HowMany&h1){
-
-
cout<<"HowMany copy constructor is called here"<<endl;
-
-
}
定义了具体的复制函数,系统就会调用处理函数了,但是这样没有处理具体的逻辑的话,执行就会出现运行时错误(bitcopy没有了,内存又没有分配),最好将系统中动态对象进行初始化,而且该与被复制的保持一致的,就保持一致:
- HowMany(const HowMany&h1){
-
-
cout<<"HowMany copy constructor is called here"<<endl;
-
-
count = new int;
-
-
*count=0;
-
-
}
执行之后,用valgrind检查就会出现明显的内存泄漏,不过调用delete
h1之后就正常了。
- construction is called here!
-
-
after construction of h:objectCount = 1
-
-
HowMany copy constructor is called here
-
-
before:0after 1
-
-
before:0after -1
-
-
after call to f():objectCount = 1
-
-
count:-1
-
-
~HowMany():objectCount = 0
复制构造函数与赋值(operator=)函数相比较,更轻(构造函数中的初始化列表就是采用了复制构造函数形式):
1.复制构造函数为构造函数,直接初始化对象,而赋值函数需要进行析构原来的对象,再重新构造一个新对象;
2.构造函数不需要进行返回,而赋值函数需要进行返回。
所以如果没有初始化的就最好调用复制构造函数,否则调用赋值函数。另外初始化列表必须在构造函数体前面
,否则由于在构造函数内部,类的成员变量被初始化了,复制构造函数就失效了。
参考资料:
thinking
in C++
阅读(1851) | 评论(0) | 转发(0) |