- C++ 基础
- C++ 首页
- C++ 概述
- C++ 环境搭建
- C++ 基本语法
- C++ 注释
- C++ Hello World
- C++ 省略命名空间
- C++ 常量/字面量
- C++ 关键字
- C++ 标识符
- C++ 数据类型
- C++ 数值数据类型
- C++ 字符数据类型
- C++ 布尔数据类型
- C++ 变量类型
- C++ 变量作用域
- C++ 多个变量
- C++ 基本输入/输出
- C++ 修饰符类型
- C++ 存储类
- C++ 运算符
- C++ 数字
- C++ 枚举
- C++ 引用
- C++ 日期和时间
- C++ 控制语句
- C++ 决策
- C++ if 语句
- C++ if else 语句
- C++ 嵌套 if 语句
- C++ switch 语句
- C++ 嵌套 switch 语句
- C++ 循环类型
- C++ while 循环
- C++ for 循环
- C++ do while 循环
- C++ foreach 循环
- C++ 嵌套循环
- C++ break 语句
- C++ continue 语句
- C++ goto 语句
- C++ 构造函数
- C++ 构造函数和析构函数
- C++ 复制构造函数
C++ 复制构造函数
复制构造函数
复制构造函数是一个构造函数,它通过用之前创建的同一类的对象初始化来创建对象。复制构造函数用于:
- 从另一个相同类型的对象初始化一个对象。
- 复制一个对象以将其作为参数传递给函数。
- 复制一个对象以从函数返回它。
如果在类中没有定义复制构造函数,编译器本身会定义一个。如果类具有指针变量并进行了一些动态内存分配,则必须有一个复制构造函数。
语法
复制构造函数最常见的形式如下所示:
classname (const classname &obj) {
// body of constructor
}
这里,obj 是一个对正在用于初始化另一个对象的对象的引用。
复制构造函数示例
以下示例演示了复制构造函数的使用
#include <iostream>
using namespace std;
class Line {
public:
int getLength( void );
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len) {
cout << "Normal constructor allocating ptr" << endl;
// allocate memory for the pointer;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj) {
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // copy the value
}
Line::~Line(void) {
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength( void ) {
return *ptr;
}
void display(Line obj) {
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main() {
Line line(10);
display(line);
return 0;
}
当以上代码编译并执行时,会产生以下结果:
Normal constructor allocating ptr Copy constructor allocating ptr. Length of line : 10 Freeing memory! Freeing memory!
复制构造函数创建新对象
您可以通过复制构造函数的概念,使用现有对象创建一个新对象。
在以下示例中,复制构造函数用于创建一个作为现有对象副本的新对象。
示例
让我们看看同一个示例,但稍作修改,使用相同类型的现有对象创建另一个对象:
#include <iostream>
using namespace std;
class Line {
public:
int getLength( void );
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len) {
cout << "Normal constructor allocating ptr" << endl;
// allocate memory for the pointer;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj) {
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // copy the value
}
Line::~Line(void) {
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength( void ) {
return *ptr;
}
void display(Line obj) {
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main() {
Line line1(10);
Line line2 = line1; // This also calls copy constructor
display(line1);
display(line2);
return 0;
}
当以上代码编译并执行时,会产生以下结果:
Normal constructor allocating ptr Copy constructor allocating ptr. Copy constructor allocating ptr. Length of line : 10 Freeing memory! Copy constructor allocating ptr. Length of line : 10 Freeing memory! Freeing memory! Freeing memory!
隐式与显式复制构造函数
在 C++ 中,有两种类型的复制构造函数,即隐式和显式。这里我们将讨论这两者之间的区别。
隐式复制构造函数
如果用户没有定义自己的复制构造函数,则编译器会自动提供一个隐式复制构造函数。它执行对象的浅拷贝,这意味着它将对象的每个成员的值复制到新对象。
何时调用隐式复制构造函数?
- 当用户按值将对象传递给函数时。
- 当用户从函数按值返回对象时。
- 当用户用相同类型的另一个对象初始化对象时(复制初始化)。
显式(用户定义)复制构造函数
它是用户定义的构造函数。这使您可以访问自定义复制行为,例如创建深拷贝而不是默认的浅拷贝。
示例
以下是 C++ 中显式和隐式复制构造函数的示例
#include <iostream>
using namespace std;
class MyClass {
private:
int value;
public:
// Constructor
MyClass(int v) : value(v) {}
// Explicit Copy Constructor
MyClass(const MyClass& other) : value(other.value) {
cout << "Explicit Copy Constructor called" << endl;
}
void display() const { cout << "Value: " << value << endl; }
};
void processValue(MyClass obj) {
// Implicit copy constructor will be called here
obj.display();
}
int main() {
MyClass obj1(10); // Constructor called
MyClass obj2 = obj1; // Explicit copy constructor called
obj1.display();
obj2.display();
processValue(obj1); // Implicit copy constructor called
return 0;
}
当以上代码编译并执行时,会产生以下结果:
Explicit Copy Constructor called Value: 10 Value: 10 Explicit Copy Constructor called Value: 10
三法则/五法则
三法则和五法则建议在定义复制构造函数 (ClassName(const ClassName& other)) 时,也应定义
三法则和五法则建议在定义**复制构造函数**(ClassName(const ClassName& other)) 时,也应定义
- 三法则
- **析构函数**(~ClassName())**。**
- 以及**复制赋值运算符**(ClassName& operator=(const ClassName& other)),以确保正确管理内存**。**
- 五法则
- **移动构造函数**(ClassName(ClassName&& other))。
- **移动赋值运算符**(ClassName& operator=(ClassName&& other))”。
这些特殊成员函数对于正确管理动态内存和其他资源(如文件处理或网络连接)在类中是必要的。
深拷贝与浅拷贝
在 C++ 中,深拷贝和浅拷贝是复制对象的两种不同方式,当类涉及动态内存管理时,它们非常重要。
1. 浅拷贝
当以这样一种方式复制对象时,原始对象和复制对象共享相同的资源,就会发生浅拷贝。这意味着复制构造函数或复制赋值运算符仅复制数据成员(如指针)的值,而不会分配新的内存或创建资源的独立副本。
示例
#include <iostream>
using namespace std;
class MyClass {
private:
int* data; // Pointer to an integer
public:
// Constructor
MyClass(int value) {
data = new int(value); // Allocate memory
}
// Shallow Copy Constructor
MyClass(const MyClass& other) {
data = other.data; // Copy pointer only
}
// Destructor
~MyClass() {
delete data; // Free memory
}
// Display the value
void showData() const { cout << "Data: " << *data << endl; }
};
int main() {
MyClass obj1(42); // Create an object
MyClass obj2 = obj1; // Use shallow copy constructor
obj1.showData();
obj2.showData();
return 0;
}
当以上代码编译并执行时,会产生以下结果:
Data: 42 Data: 42 free(): double free detected in tcache 2
2. 深拷贝
当通过为其自身资源的副本分配新内存来复制对象时,就会发生深拷贝,确保原始对象和复制对象完全独立。避免双重释放错误或悬空指针。
示例
#include <iostream>
using namespace std;
class MyClass {
private:
int* data; // Pointer to an integer
public:
// Constructor: Dynamically allocate memory
// and initialize with value
MyClass(int value) { data = new int(value); }
// Deep Copy Constructor
// Allocates new memory and copies the value
MyClass(const MyClass& other) { data = new int(*other.data); }
// Destructor to clean up memory
~MyClass() { delete data; }
// Display the value
void showData() const { cout << "Data: " << *data << endl; }
};
int main() {
MyClass obj1(42); // Create an object
MyClass obj2 = obj1; // Use deep copy constructor
obj1.showData(); // Display data from obj1
obj2.showData(); // Display data from obj2
return 0;
}
当以上代码编译并执行时,会产生以下结果:
Data: 42 Data: 42