C++学习笔记(一).拷贝构造函数
2007-07-10 23:57
239 查看
在C和C++中,对于内部类型(如:int、float、char等)的普通变量通过传值方式作为函数参数和返回值传递时,直接用位拷贝的方式来实现是没问题的;但是在C++中,对于对象(其类型为我们自定义的类类型),如果通过简单的位拷贝来实现就会有问题,这样不能对类对象进行真正的初始化以维护它的完整性。(可以想:如果类中含有指针的话,如果通过位拷贝,那么新的对象的指针将指向什么内容?它们将与新的内存块相连还是和源对象指向同一块内存呢?)为解决防止位拷贝,可通过定义自己的函数来实现。这个函数是什么样的呢?
1)由于是创建一个新的对象,所以应该是一个构造函数;
2)由于是用它来实现从已有对象创建新对象,那怎样把已有对象联系起来呢?可以把已有对象作为源对象作为这个函数的单一参数传递。由于这个源对象不能通过值传递的方式传入构造函数(因为定义这个函数就是为了处理按值传递方式),而按句法传递一个指针是没有意义的,所以就用源对象的引用来传递。
这个函数就是拷贝构造函数。它经常被称为X(X&)(它叫做类X的外在表现)。
这样,有了拷贝构造函数,在用现有的对象创建新对象时,编译器将不再使用位拷贝,而是调用我们的拷贝构造函数。对于使用组合(或继承)的类,如果我们没有定义自己的拷贝构造函数,那么编译器会通过递归调用它所有成员对象(或基类)的拷贝构造函数来自动创建一个拷贝构造函数。编译器获得拷贝构造函数的过程被称为成员方法初始化。如下例,可尝试把Another类中的拷贝构造函数屏蔽看其运行结果:
#include<iostream>
using namespace std;
class exeEleven
{
int i;
public:
exeEleven( int ii = 0):i(ii)
{
cout<<"enter exeEleven()....."<<endl;
}
exeEleven(const exeEleven& h)
{
cout<<"enter exeEleven(exeEleven&)...."<<endl;
}
};
class WoCC
{
int a;
public:
WoCC(const int b=0):a(b)
{
cout<<"WoCC's constructor"<<endl;
}
WoCC(const WoCC& m)
{
cout<<"in WoCC's copy-constructor"<<endl;
}
};
class Another //combination
{
int i;
exeEleven ee;
WoCC wo;
public:
Another( int ii = 0):i(ii),ee(20)
{
cout<<"enter Another()..."<<endl;
}
Another(const Another& h) //----------- try to closs this function
{
cout<<"enter Another(Another&)..."<<endl;
}
};
void main()
{
cout<<"create a1----->"<<endl;
Another a1(4);
cout<<"create a2----->"<<endl;
Another a2 = a1;
}
另外,通常在一个类中:如果我们没定义它的构造函数时,编译器会自动为它创建一个什么也不做的默认的构造函数;如果我们没有创建它的拷贝构造函数,编译器会自动创建一个仅执行位拷贝的拷贝构造函数;如果我们创建了它的拷贝构造函数,而没创建它的构造函数,那么编译器将不再自动为它创建构造函数,而是报错。
什么时候需要拷贝构造函数,而什么时候不需要拷贝构造函数呢?只有当准备用按值传递的方式传递类对象时,才需要拷贝构造函数;否则,则不需要。
为了避免当没为类创建拷贝构造函数时,编译器会自动创建一个位拷贝的拷贝构造函数(组合和继承类除外),我们可以在类内声明一个私有的拷贝构造函数,不必定义,(除非成员函数或友元函数需要执行按值方式的传递),这样编译器就不会再自动创建了。
1)由于是创建一个新的对象,所以应该是一个构造函数;
2)由于是用它来实现从已有对象创建新对象,那怎样把已有对象联系起来呢?可以把已有对象作为源对象作为这个函数的单一参数传递。由于这个源对象不能通过值传递的方式传入构造函数(因为定义这个函数就是为了处理按值传递方式),而按句法传递一个指针是没有意义的,所以就用源对象的引用来传递。
这个函数就是拷贝构造函数。它经常被称为X(X&)(它叫做类X的外在表现)。
这样,有了拷贝构造函数,在用现有的对象创建新对象时,编译器将不再使用位拷贝,而是调用我们的拷贝构造函数。对于使用组合(或继承)的类,如果我们没有定义自己的拷贝构造函数,那么编译器会通过递归调用它所有成员对象(或基类)的拷贝构造函数来自动创建一个拷贝构造函数。编译器获得拷贝构造函数的过程被称为成员方法初始化。如下例,可尝试把Another类中的拷贝构造函数屏蔽看其运行结果:
#include<iostream>
using namespace std;
class exeEleven
{
int i;
public:
exeEleven( int ii = 0):i(ii)
{
cout<<"enter exeEleven()....."<<endl;
}
exeEleven(const exeEleven& h)
{
cout<<"enter exeEleven(exeEleven&)...."<<endl;
}
};
class WoCC
{
int a;
public:
WoCC(const int b=0):a(b)
{
cout<<"WoCC's constructor"<<endl;
}
WoCC(const WoCC& m)
{
cout<<"in WoCC's copy-constructor"<<endl;
}
};
class Another //combination
{
int i;
exeEleven ee;
WoCC wo;
public:
Another( int ii = 0):i(ii),ee(20)
{
cout<<"enter Another()..."<<endl;
}
Another(const Another& h) //----------- try to closs this function
{
cout<<"enter Another(Another&)..."<<endl;
}
};
void main()
{
cout<<"create a1----->"<<endl;
Another a1(4);
cout<<"create a2----->"<<endl;
Another a2 = a1;
}
另外,通常在一个类中:如果我们没定义它的构造函数时,编译器会自动为它创建一个什么也不做的默认的构造函数;如果我们没有创建它的拷贝构造函数,编译器会自动创建一个仅执行位拷贝的拷贝构造函数;如果我们创建了它的拷贝构造函数,而没创建它的构造函数,那么编译器将不再自动为它创建构造函数,而是报错。
什么时候需要拷贝构造函数,而什么时候不需要拷贝构造函数呢?只有当准备用按值传递的方式传递类对象时,才需要拷贝构造函数;否则,则不需要。
为了避免当没为类创建拷贝构造函数时,编译器会自动创建一个位拷贝的拷贝构造函数(组合和继承类除外),我们可以在类内声明一个私有的拷贝构造函数,不必定义,(除非成员函数或友元函数需要执行按值方式的传递),这样编译器就不会再自动创建了。
相关文章推荐
- c++学习笔记(二):c++拷贝构造函数应用的四种场景
- c++学习笔记--拷贝构造函数
- C++学习笔记_5:拷贝构造函数
- C++学习笔记-----在重载的赋值运算函数中调用拷贝构造函数
- C++ 学习笔记(13)拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符、析构函数、右值引用、引用限定符
- C++学习笔记(构造函数和拷贝构造函数)
- C++学习笔记---拷贝构造函数
- 我的学习笔记——c++拷贝构造函数,重载赋值操作符
- C++学习笔记――引用与拷贝构造函数
- Effective C++ 学习笔记:为含指针变量的类声明一个拷贝构造函数和一个赋值操作符
- 学习笔记:C++ primer Plus chap5
- C++基础知识学习笔记(一)
- c++学习笔记 -- 构造函数
- C++ 开发学习笔记:C++ 数据互相转换
- C++学习笔记--泛型算法
- C++学习笔记(六)继承属性
- c++学习笔记之函数引用返回
- c++学习笔记
- c++学习笔记(十一):函数重载VS函数重写
- 【C++学习笔记】09_一维数组