码迷,mamicode.com
首页 > 编程语言 > 详细

C++ Primer 学习笔记_20_类与数据抽象(6)_深拷贝与浅拷贝、空类与空数组

时间:2015-07-29 19:19:06      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:c++   c++ primer   类与数据抽象   

C++ Primer 学习笔记_20_类与数据抽象(6)_深拷贝与浅拷贝、空类与空数组 

一、深拷贝与浅拷贝

    浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换而言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。

    深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换而言之,深拷贝把要复制的对象所引用的对象都复制了一遍。

    浅拷贝可能会导致运行时错误,特别时在对象的创建与删除过程中。

    说得简单点,假设一个类有指针成员,如果只是分配指针本身的内存,那就是浅拷贝,如下图。如果在拷贝的时候顺带连指针指向的内存也分配了,就称为深拷贝,如下图(t 从 s 拷贝而来)。

技术分享


【举个例子】

struct Test
{
    char *ptr;
};
void shallow_copy(Test& src, Test& dest)
{
    dest.ptr = src.ptr;
}
void deep_copy(Test& src, Test& dest)
{
    dest.ptr = malloc(strlen(src.ptr) + 1);
    memcpy(dest.ptr, src.ptr);
}

    浅拷贝造成的问题是有两个指针指向同块内存,delete 其中一个指针,那么剩下的指针将成为野指针。编译器合成的默认拷贝构造函数和赋值运算符是浅拷贝的,如果只是普通成员的赋值,浅拷贝也是可以的。

#include <string.h>
#include <cstring>
#include <iostream>
using  namespace std;

class String
{
public:
    String( char *str =  "");
    ~String();
    String( const String &other);
    String & operator=( const String &other);
    void Display();
private:
     char *AllocAndCpy( char *str);
     char *str_;
};

String::String( char *str /* = */)
{
    str_ = AllocAndCpy(str);
}

String::~String()
{
     delete[] str_;
}

String::String( const String &other)
{
    str_ = AllocAndCpy(other.str_);
}

String &String:: operator =( const String &other)
{
    if ( this == &other)
         return * this;

    delete[] str_;
    str_ = AllocAndCpy(other.str_);
    return * this;
}


char *String::AllocAndCpy( char *str)
{
    int len = strlen(str) +  1;
    char *tmp =  new  char[len];
    memset(tmp,  0, len);
    strcpy(tmp, str);
    return tmp;
}

void String::Display()
{
    cout << str_ << endl;
}

int main( void)
{
    String s1( "AAA");
    s1.Display();
    String s2 = s1;      // 调用拷贝构造函数
    // 系统提供的默认拷贝构造函数实施的是浅拷贝 s2.str_ = s1.str_

    String s3;
    s3.Display();
    s3 = s2;             // 调用等号运算符
    // 系统提供的默认等号运算符实施的是浅拷贝 s3.str_ = s2.str_;
    // s3.operator=(s2);
    s3.Display();
    // 要让对象是独一无二的,我们要禁止拷贝
    // 方法是将拷贝构造函数与=运算符声明为私有,并且不提供它们的实现
    return  0;
}

运行结果:
AAA 
AAA 

解释:上面程序中String 类有一个char* str_ 成员,故实现了深拷贝,这样不会造成内存被释放两次的错误,或者修改指针指向的内存会影响另一个对象的错误。此外,如果我们想让对象是独一无二的,需要禁 止拷贝,只需要将拷贝构造函数和等号运算符声明为私有,并且不提供它们的实现。

注意:在编写派生类的赋值函数时,不要忘记对基类的数据成员重新赋值,可以通过调用基类的赋值函数来实现,比如在

Derived& Derived::operator=(const Derived& other) { } 中调用Base::operator=(other);


二、空类与空数组

空类默认产生的成员:

class Empty {};
Empty(); // 默认构造函数
Empty( const Empty& );// 默认拷贝构造函数
~Empty(); // 默认析构函数
Empty& operator=( const Empty& );  // 默认赋值运算符
Empty* operator&();              // 取址运算符
const Empty* operator&() const;   // 取址运算符 const

【例子】
#include <iostream>
using  namespace std;

class Empty
{
public:
    Empty * operator&()
    {
        cout <<  "AAAA" << endl;
         return  this;
    }

     const Empty * operator&()  const
    {
        cout <<  "BBBB" << endl;
         return  this;
    }
};

int main( void)
{
    Empty e;
    Empty *p = &e;       // 等价于e.operator&();
     const Empty e2;
     const Empty *p2 = &e2;

    cout <<  sizeof(Empty) << endl;

     return  0;
}

运行结果:

AAAA
BBBB
1

解释:可以看到分别调用了两个取地址运算符函数,而且空类的大小为1个字节。

【例子】

体会一下下面的程序结果:

#include<iostream>
using  namespace std;

int main()
{
    int a[ 0];
    class B {};
    struct C
    {
         int  m;
         int  n;
         char buffer[];
    };
    class D
    {
         int  s[ 0];
    };

    cout <<  "sizeof(a)=" <<  sizeof(a) << endl;  //0
    cout <<  "B{}=" <<  sizeof(B) << endl;  //1
    cout <<  "C=" <<  sizeof(C) << endl;  //8
    cout <<  "D=" <<  sizeof(D) << endl;  //0
    return  0;

}
运行结果:
sizeof(a)=0 
B{}=1 
C=8 
D=0

参考:

C++ primer 第四版
Effective C++ 3rd

http://blog.csdn.net/jnu_simba/article/details/9183425

http://blog.csdn.net/zjf280441589/article/details/24954205
C++编程规范

版权声明:本文为博主原创文章,未经博主允许不得转载。

C++ Primer 学习笔记_20_类与数据抽象(6)_深拷贝与浅拷贝、空类与空数组

标签:c++   c++ primer   类与数据抽象   

原文地址:http://blog.csdn.net/keyyuanxin/article/details/47131649

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!