广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++中的复制构造函数详解
  • 766
分享到

C++中的复制构造函数详解

2024-04-02 19:04:59 766人浏览 八月长安
摘要

目录复制构造函数复制构造函数的三种调用复制构造函数的禁用深拷贝与浅拷贝一定会生成默认复制构造函数吗?参考 总结普通变量的复制 有时我们会在定义一个变量的同时使用另一个变量来初始化它。

普通变量的复制

有时我们会在定义一个变量的同时使用另一个变量来初始化它。


int a_variable=12;
int new_variable(a_variable);

通过已有的同类型变量来初始化自身很有用。
对自定义类型的对象是否可以通过一个存在的对象方便的复制呢?

复制构造函数

复制构造函数又叫做拷贝构造函数,它只有一个参数(既然需要复制,一个就够了,若传入两个相同对象则没有意义,若传入两个不同的对象,就没必要叫做复制构造函数了),参数类型为本类的引用。

如果程序员没有编写复制构造函数,编译器会自动生成复制构造函数,在复制构造函数中按照成员变量进行逐字节复制(初学可以这样理解,实际上,个别编译器并不总是会自动生成复制构造函数,它们可能采用直接将源对象的各个值复制到目标对象对应的成员变量上,后面会介绍这种情况)。


class MyDate
{
	int day_;
	int year_;
public:
	MyDate(int day, int year)
	{
		day_ = day;
		year_ = year;
	}
	MyDate(const MyDate& date)
	{
		day_ = date.day_;
		year_ = date.year_;
		cout << "Date类的复制构造函数执行了!" << endl;
	}
	~MyDate() {}
};
void test()
{
	MyDate date1(12, 2021);
	MyDate date2(date1);
}
int main()
{
	test();
	system("pause");
	return 0;
}

执行为:

在这里插入图片描述

对于MyDate(const MyDate& date)参数列表中的const,因为复制构造函数参数另一个对象引用,如果不加const修饰,在此复制构造函数中可能会改变原对象的内容,为了安全起见,应加尽加。

如果程序员编写了复制构造函数,则编译器就不会生成默认复制构造函数了(所以编写了复制构造函数之后就尽量在函数体内实现复制操作,不要定义了复制构造函数却不完全或不实现复制操作)。

另一方面,所有的构造函数(包括复制构造函数)、析构函数都无法从父类继承,只能自己实现。

构造函数如果只有一个参数且这个参数为本类对象,就会与复制构造函数起冲突。如图:

在这里插入图片描述

复制构造函数的三种调用

复制构造函数在以下3种情况下会被调用:

1.当使用一个A类型对象去初始化另一个A类型的对象时(刚创建好的,已创建好的不算),会调用复制构造函数。注意观察以下代码:


Date date1(12,2012);//创建一个date1对象
Date date2(date1);//调用复制构造函数
Date date3=date1;//也会调用复制构造 函数
date2=date1;//date2已存在,不会调用复制构造函数,会调用赋值=操作函数

在这里插入图片描述

可以看到复制构造函数只调用了两次。

2.我们都知道c++传参有传值和传引用(指针本质上是传值,传的是实参的地址)。如果函数参数是一个自定义对象,那么会调用该自定义对象的复制构造函数。

在传值的时候,编译器会开辟一个空间(创建了一个临时对象)存储实参的值(这个过程会将实参的各个值分配复制给临时对象),再将该值压入栈中。


//类声明略
void TestFunction(MyDate date)
{
	cout << "TestFunction()执行了!" << endl;
}
void test()
{
	MyDate date1(12, 2021);
	TestFunction(date1);
}
//main函数略

结果如下:

在这里插入图片描述

3.如果函数的返回值是类MyDate的对象,则函数返回时,会调用该对象的复制构造函数。


//类声明略
MyDate TestFunction2()
{
	MyDate date1(12, 2021);
	cout << &date1 << endl;
	return date1;
}
void test()
{
	cout << &TestFunction2() << endl;
}
//main函数省略

从复制构造函数内的输出被两个地址输出夹住即可看出在哪里调用了复制构造函数。

在这里插入图片描述

复制构造函数的禁用

如果不希望自定义类型的复制构造函数被调用。

仅仅不编写复制构造函数是不行的,编译器可能会自动生成默认的复制构造函数。应该使用private修饰复制构造函数(这时编译器就不会生成自动复制构造函数),此时不要实现这个复制构造函数,如下:

在这里插入图片描述

这样便既禁止了用户调用此复制构造函数,又禁止了用户通过其他成员函数或友元函数间接地调用它(如果我们仅仅把复制构造函数声明为private,声明并实现了复制构造函数,虽然避免了用户直接调用,但成员函数和友元函数还是可以调用,只有不实现它才能永绝后患)。

Bjarne Stroustrup认为如果你希望禁止某些操作,就把它定义为一个私有的成员函数即可。

深拷贝与浅拷贝

如果成员变量含有指针类型,默认复制构造函数并不会将指针指向的内存中的值进行赋值,仅仅将指针存储的值(也就是一个地址)复制了一次(与我们所希望的不一致)。这时两个指针指向了同一块内存空间,一旦一种一个指针所属的对象声明周期结束,会调用它自己的析构函数回收指针指向的内存空间。这时另一个指针遍指向了一个垃圾值,这个指针也变为了空悬指针。以上就是我们常提到的浅拷贝。

实际开发当中要竭力避免以上清情况的发生(当成员变量含有指针或动态分配内存等情况)。

深拷贝如下:


class MyDate
{
private:
	char* buffer_;
public:
	MyDate(const char *init);//实现略
	MyDate(const MyDate &date)
	{
		if(date.buffer_!=nullptr)
		{
			buffer_=new char[strlen(date.buffer_)+1];
			strcpy(buffer_,date.buffer_);
		}
		else
		{
			buffer=nullptr;
		}
	}
}

复制构造函数先检查date中的buffer_的字符串大小,然后分配此大小+1的内存给新创建的对象的buffer_(strlen函数不会计算'\0'字符),最后使用strcpy函数将date的buffer_指向的内存中的内容复制到新创建的对象的buffer_所指向的空间(strcpy函数会吧'\0'字符一并复制)。最后实现了两个指针指向了不同的存储空间(两个空间的内容相同)。

在这里插入图片描述

如果我们要编写需要字符的成员时,尽量使用string。它会像其他成员变量一样进行复制,因为string有自己的复制构造函数。

一定会生成默认复制构造函数吗?

我们前面提到如果程序员没有定义自己的复制构造函数,编译器会为我们生成一个默认复制构造函数。

实际上以下4中情况编译器会为我们生成默认复制构造函数。

1.没有为类编写复制构造函数,但该类含有自定义类型或string等类型作为成员变量时。

2.没有为类编写复制构造函数,但该类继承了一个含有复制构造函数的类时,编译器会生成默认复制构造函数,在该函数中调用父类的复制构造函数。

3.没有为类编写复制构造函数,但是该类定义了虚函数或者该类的父类定义了虚函数。,

4.没有为类编写复制构造函数,但是该类有虚基类。

参考

The C++ Programming Language (美) Bjarne Stroustrup

Thinking in C++ Volume One:Introduction toStandard C++ (美)Bruce Eckel

C++新经典 对象模型 王建伟

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: C++中的复制构造函数详解

本文链接: https://www.lsjlt.com/news/136164.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++中的复制构造函数详解
    目录复制构造函数复制构造函数的三种调用复制构造函数的禁用深拷贝与浅拷贝一定会生成默认复制构造函数吗?参考 总结普通变量的复制 有时我们会在定义一个变量的同时使用另一个变量来初始化它。...
    99+
    2022-11-12
  • C++中构造函数详解
    构造函数按参数为为:有参构造函数和无参构造函数 按类型分为:普通构造函数和拷贝构造函数 构造函数的三种调用方法:括号法,显示法,隐式转换法; //括号法 Person p1; ...
    99+
    2022-11-13
  • C++中的构造函数详解
    目录普通变量的初始化构造函数一定会生成默认构造函数吗?防止隐式类型转换赋值与初始化的区别对象的计数成员初始化的顺序类的引用成员构造函数使用注意事项参考总结普通变量的初始化 当我们在定...
    99+
    2022-11-12
  • 详解C++构造函数
    目录1.作用2.代码举例2.1 示例1:2.2 示例2:3. 使用3.1 使用构造函数初始化3.2 有参数的构造函数3.3 默认的构造函数4. 成员初始化列表例1:正常初始化例2:成...
    99+
    2022-11-12
  • C#构造函数详解
    一、简介 构造函数,基本用法是在类对象声明的时候完成初始化工作。 二、实例构造函数 1、构造函数的名字与类名相同。 2、使用 new 表达式创建类的对象或者结构(例如int)时,会调...
    99+
    2022-11-13
  • C++构造函数详解
    文章转自公众号:Coder梁(ID:Coder_LT) 上一篇文章我们介绍了定义了类,在使用之前,往往还需要对类进行初始化。这篇介绍的就是对类进行初始化的方法。 像是结构体,我们可以...
    99+
    2022-11-12
  • C#中怎么复制构造函数
    这期内容当中小编将会给大家带来有关C#中怎么复制构造函数,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。我们在讨论C#复制构造函数之前想要明白什么是复制构造函数?我们知道构造函数是用来初始化我们要创建实例的...
    99+
    2023-06-18
  • C++:构造函数,析构函数详解
    目录前言一、面向对象二、构造函数1.基本概念2.构造函数重载1.构造函数分类2.有参构造函数:3.有参构造函数3个调用规则:4.拷贝构造函数5.析构函数总结前言 上期了解C++类中有...
    99+
    2022-11-12
  • C++中的拷贝构造函数详解
    目录C++拷贝构造函数(复制构造函数)详解1) 为什么必须是当前类的引用呢?2) 为什么是 const 引用呢?默认拷贝构造函数总结C++拷贝构造函数(复制构造函数)详解 拷贝和复制...
    99+
    2022-11-13
  • c++特殊构造函数详解
    目录前言拷贝构造函数一、什么是拷贝构造函数二、调用时机注意浅拷贝和深拷贝总结前言 众所周知,构造函数的作用是类在创建对象时的初始化,而拷贝构造函数则是构造函数里的一种特殊构造。 拷贝...
    99+
    2022-11-12
  • C#中怎么实现复制构造函数
    C#中怎么实现复制构造函数,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。C#复制构造函数的一点认识:某些编程语言的类提供了复制构造函数,即从当前类实例构造一个新的类实例。在...
    99+
    2023-06-18
  • C++超详细讲解构造函数
    目录类的6个默认成员函数构造函数特性编译器生成的默认构造函数成员变量的命名风格类的6个默认成员函数 如果我们写了一个类,这个类我们只写了成员变量没有定义成员函数,那么这个类中就没有函...
    99+
    2022-11-13
  • C++构造函数+复制构造函数+重载等号运算符调用
    目录前言:1、赋值和初始化的区别2、初始化和赋值分别调用哪个函数?3、编写测试类前言: 初学C++发现了下面这个问题,其中Duck是一个已知的类,并以多种方式指定对象的值: Duck...
    99+
    2022-11-13
  • C++中拷贝构造函数的总结详解
    1.什么是拷贝构造函数: 拷贝构造函数嘛,当然就是拷贝和构造了。(其实很多名字,只要静下心来想一想,就真的是顾名思义呀)拷贝又称复制,因此拷贝构造函数又称复制构造函数。百度百科上是这...
    99+
    2022-11-15
    拷贝构造函数 C++
  • C#中怎么实现构造函数的复制操作
    今天就跟大家聊聊有关C#中怎么实现构造函数的复制操作,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。C#复制构造函数的编写代码:class Person  ...
    99+
    2023-06-18
  • C++中构造函数与析构函数的详解及其作用介绍
    目录构造函数默认构造函数有参构造函数析构函数析构函数例子析构函数执行时机局部对象全局对象构造函数 构造函数 (constructor) 是一种特殊的成员函数. 它会在每次创建类的新对...
    99+
    2022-11-12
  • C# Record构造函数的行为更改详解
    如何更改 C# Record 构造函数的行为 Record[1] 是 C# 9 中的一个新功能。Record是从Structs[2]借用的特殊类, 因为它们具有 基于值的相等性,您可...
    99+
    2022-11-12
  • C++构造函数的初始化列表详解
    目录1.问题2.解决方法(初始化列表)3.顺序问题总结 1.问题 class A { private: int m_a; public: A(int a) { cout ...
    99+
    2022-11-12
  • C++超详细讲解拷贝构造函数
    目录构造函数特征编译器生成的拷贝构造拷贝构造的初始化列表显式定义拷贝构造的误区结论构造函数 只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对...
    99+
    2022-11-13
  • C++构造函数,复制构造函数和重载等号运算符怎么调用
    本篇内容主要讲解“C++构造函数,复制构造函数和重载等号运算符怎么调用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++构造函数,复制构造函数和重载等号运算符怎么调用”吧!前言:初学C++发现...
    99+
    2023-06-29
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作