首页IT科技拷贝构造函数原理(C++:拷贝构造函数)

拷贝构造函数原理(C++:拷贝构造函数)

时间2025-09-16 15:06:21分类IT科技浏览5250
导读:1. 拷贝和拷贝构造函数 拷贝和复制是一个意思,对应的英文单词都是copy。对于计算机来说,拷贝是指用一份原有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将 Word 文档拷贝到U盘去复印店打印,将 D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建...

1. 拷贝和拷贝构造函数

拷贝和复制是一个意思                ,对应的英文单词都是copy                。对于计算机来说                      ,拷贝是指用一份原有的                、已经存在的数据创建出一份新的数据       ,最终的结果是多了一份相同的数据                      。例如            ,将 Word 文档拷贝到U盘去复印店打印                       ,将 D 盘的图片拷贝到桌面以方便浏览          ,将重要的文件上传到百度网盘以防止丢失等        ,都是「创建一份新数据」的意思       。

在 C++ 中                        ,拷贝并没有脱离它本来的含义              ,只是将这个含义进行了“特化              ”    ,是指用已经存在的对象创建出一个新的对象            。从本质上讲                        ,对象也是一份数据                  ,因为它会占用内存                       。严格来说,对象的创建包括两个阶段                    ,首先要分配内存空间                      ,然后再进行初始化:

分配内存很好理解    ,就是在堆区                      、栈区或者全局数据区留出足够多的字节          。这个时候的内存还比较“原始                       ”                ,没有被“教化        ”                      ,它所包含的数据一般是零值或者随机值       ,没有实际的意义        。 初始化就是首次对内存赋值            ,让它的数据有意义                        。注意是首次赋值                       ,再次赋值不叫初始化              。初始化的时候还可以为对象分配其他的资源(打开文件       、连接网络            、动态分配内存等)          ,或者提前进行一些计算(根据价格和数量计算出总价                       、根据长度和宽度计算出矩形的面积等)等    。说白了        ,初始化就是调用构造函数                        。

很明显                        ,这里所说的拷贝是在初始化阶段进行的              ,也就是用其它对象的数据来初始化新对象的内存                  。那么    ,如何用拷贝的方式来初始化一个对象呢?其实这样的例子比比皆是                        ,string 类就是一个典型的例子。

#include <iostream> #include <string> using namespace std; void func(string str){ cout<<str<<endl; } int main(){ string s1 = "http://c.biancheng.net"; string s2(s1); string s3 = s1; string s4 = s1 + " " + s2; func(s1); cout<<s1<<endl<<s2<<endl<<s3<<endl<<s4<<endl; return 0; }

运行结果:

http://c.biancheng.net http://c.biancheng.net http://c.biancheng.net http://c.biancheng.net http://c.biancheng.net http://c.biancheng.net

s1          、s2        、s3                        、s4 以及 func() 的形参 str                  ,都是使用拷贝的方式来初始化的                    。

对于 s1,表面上看起来是将一个字符串直接赋值给了 s1                    ,实际上在内部进行了类型转换                      ,将 const char * 类型转换为 string 类型后才赋值的    ,这其实涉及到C++转换构造函数的知识                      。s4 也是类似的道理    。

对于 s1              、s2    、s3                        、s4                ,都是将其它对象的数据拷贝给当前对象                      ,以完成当前对象的初始化                。

对于 func() 的形参 str       ,其实在定义时就为它分配了内存            ,但是此时并没有初始化                       ,只有等到调用 func() 时          ,才会将其它对象的数据拷贝给 str 以完成初始化                      。

当以拷贝的方式初始化一个对象时        ,会调用一个特殊的构造函数                        ,就是拷贝构造函数(Copy Constructor)       。

下面的例子演示了拷贝构造函数的定义和使用:

#include <iostream> #include <string> using namespace std; class Student{ public: Student(string name = "", int age = 0, float score = 0.0f); //普通构造函数 Student(const Student &stu); //拷贝构造函数(声明) public: void display(); private: string m_name; int m_age; float m_score; }; Student::Student(string name, int age, float score): m_name(name), m_age(age), m_score(score){ } //拷贝构造函数(定义) Student::Student(const Student &stu){ this->m_name = stu.m_name; this->m_age = stu.m_age; this->m_score = stu.m_score; cout<<"Copy constructor was called."<<endl; } void Student::display(){ cout<<m_name<<"的年龄是"<<m_age<<"              ,成绩是"<<m_score<<endl; } int main(){ Student stu1("小明", 16, 90.5); Student stu2 = stu1; //调用拷贝构造函数 Student stu3(stu1); //调用拷贝构造函数 stu1.display(); stu2.display(); stu3.display(); return 0; }

运行结果:

Copy constructor was called. Copy constructor was called. 小明的年龄是16    ,成绩是90.5 小明的年龄是16                        ,成绩是90.5 小明的年龄是16                  ,成绩是90.5

第 8 行是拷贝构造函数的声明,第 20 行是拷贝构造函数的定义            。拷贝构造函数只有一个参数                    ,它的类型是当前类的引用                      ,而且一般都是 const 引用                       。

1.1 为什么必须是当前类的引用呢?

如果拷贝构造函数的参数不是当前类的引用    ,而是当前类的对象                ,那么在调用拷贝构造函数时                      ,会将另外一个对象直接传递给形参       ,这本身就是一次拷贝            ,会再次调用拷贝构造函数                       ,然后又将一个对象直接传递给了形参          ,将继续调用拷贝构造函数……这个过程会一直持续下去        ,没有尽头                        ,陷入死循环          。

只有当参数是当前类的引用时              ,才不会导致再次调用拷贝构造函数    ,这不仅是逻辑上的要求                        ,也是 C++ 语法的要求        。

1.2 为什么是 const 引用呢?

拷贝构造函数的目的是用其它对象的数据来初始化当前对象                  ,并没有期望更改其它对象的数据,添加 const 限制后                    ,这个含义更加明确了                        。

另外一个原因是                      ,添加 const 限制后    ,可以将 const 对象和非 const 对象传递给形参了                ,因为非 const 类型可以转换为 const 类型              。如果没有 const 限制                      ,就不能将 const 对象传递给形参       ,因为 const 类型不能转换为非 const 类型            ,这就意味着                       ,不能使用 const 对象来初始化当前对象了    。

以上面的 Student 类为例          ,将 const 去掉后        ,拷贝构造函数的原型变为:

Student::Student(Student &stu);

此时                        ,下面的代码就会发生错误:

const Student stu1("小明", 16, 90.5); Student stu2 = stu1; Student stu3(stu1);

stu1 是 const 类型              ,在初始化 stu2                  、stu3 时    ,编译器希望调用Student::Student(const Student &stu)                        ,但是这个函数却不存在                  ,又不能将 const Student 类型转换为 Student 类型去调用Student::Student(Student &stu),所以最终调用失败了                        。

当然                    ,也可以再添加一个参数为 const 引用的拷贝构造函数                      ,这样就不会出错了                  。换句话说    ,一个类可以同时存在两个拷贝构造函数                ,一个函数的参数为 const 引用                      ,另一个函数的参数为非 const 引用。

2. 默认拷贝构造函数

其实       ,即使我们没学习过拷贝构造函数            ,实际上却已经在使用拷贝的方式创建对象了                       ,并且也没有引发什么错误                    。这是因为          ,如果程序员没有显式地定义拷贝构造函数        ,那么编译器会自动生成一个默认的拷贝构造函数                      。这个默认的拷贝构造函数很简单                        ,就是使用“老对象           ”的成员变量对“新对象                      ”的成员变量进行一一赋值              ,和上面 Student 类的拷贝构造函数非常类似    。

对于简单的类    ,默认拷贝构造函数一般是够用的                        ,我们也没有必要再显式地定义一个功能类似的拷贝构造函数                。但是当类持有其它资源时                  ,如动态分配的内存、打开的文件                    、指向其他数据的指针                      、网络连接等,默认拷贝构造函数就不能拷贝这些资源                    ,我们必须显式地定义拷贝构造函数                      ,以完整地拷贝对象的所有数据                      。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
网站搜索引擎优化方案范文(搜索引擎的网站的优化技巧主要有哪些?) 苹果cmsv10泛解析站群(优秀的苹果CMS教程,助您轻松打造精美网站)