拷贝构造函数与赋值构造函数

A(const A&);   //默认拷贝构造函数

A& operater = (const A& a);   //默认赋值函数

【弊端】:若类中包含指针成员或引用成员,这两个默认的函数可能隐含错误。

(1)   原有的内存没有释放,造成内存泄漏;

(2)   使两个对象中的指针成员指向同一块内存,任何一方变动都会影响另一方;

(3)   在对象析构时,delete两次。

 

拷贝构造函数:在创建对象,并用另一个已经存在的对象来初始化它时调用。

如:String a("hello");   //调用带参数的构造函数

       String b(a);   //或是String b = a,调用拷贝构造函数

赋值函数:把一个对象赋值给另一个已经存在的对象,使得已经存在的那个对象和源对象具有相同的状态。

如:String c;

        c = a;

 

类String拷贝构造函数在函数入口处不用与NULL比较,因为引用不可能是NULL,而指针可以为NULL,所以在默认构造函数中需与NULL比较。

例1:类String的拷贝构造函数和拷贝赋值函数

String::String(const String& other)

{

    int length = strlen(other.m_data);

m_data = new char[length + 1];

    strcpy(m_data, other.m_data);

m_size = length;

}

 

String& String::operator = (const String& other)

{

//(1)检查自赋值

if (this != &other)  //地址相等才认为是同一对象,不能错写成if (*this = other)

{

//(2)分配新的内存空间,并拷贝内容

char* temp = new char[strlen(other.m_data) + 1];

strcpy(temp, other.m_data );  //连'/0'一起拷贝

//(3)释放原有的内存资源

delete [ ] m_data;

m_data = temp;

m_size = strlen(other.m_data);

}

//(4)返回本对象的引用

return *this;  //返回本对象的引用,目的是为了实现a=b=c这样的链式表达式

}

如果先把原有的内存释放,如果后来内存重分配失败,就惨了!所以,先分配内存给一个临时指针,万一分配失败也不会改变this对象。

 

如果我们不想编写拷贝构造函数和拷贝赋值函数(不想拷贝对象),又不允许使用编译器自动生成的默认函数,只需将拷贝构造函数和拷贝赋值函数声明为private,并且不实现它们。

 

基类的构造函数、析构函数和赋值函数不能被派生类继承。如果存在类继承关系,则在编写基本函数时应该注意:

(1)   派生类的构造函数应该其初始化列表里显式地调用基类构造函数;

(2)   如果基类是多态类(包括虚函数的类),则必须把基类的析构函数定义为虚函数,这样可以像其他函数一样实现动态绑定,否则可能会造成内存泄漏;

如:Base *pB = new Derived;

     是虚函数,析构时先调用Derived::~Derived(),再调用Base::~Base()

     不是虚函数,则直接调用Base::~Base(),因此派生类对象的内存不会释放,造成内存泄漏

(3)   在编写派生类的赋值函数时,要记得对基类的数据成员重新赋值,可以通过调用基类的赋值函数来实现。

如:

Derived& Derived::operater = (const Derived& other)

{

//(1)检查自赋值

if (this != &other)

{

//(2)对基类的数据成员重新赋值

Base::operator = (other);

//(3)对派生类的数据成员赋值

m_x = other.m_x;

m_y = other.m_y;

m_z = other.m_z;

}

//(4)返回本对象的引用

return *this;

}

------------------------

 

文章转自互联网。。。

发布了45 篇原创文章 · 获赞 3 · 访问量 13万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章