构造.析构.深拷贝和浅拷贝

本文详细解析了C++中对象的构造与析构过程,包括构造函数与析构函数的特点、如何进行对象初始化及内存管理,还介绍了拷贝构造函数的深拷贝与浅拷贝区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 类与对象的编译原理
每个对象所占用的内存空间都等于类中全部数据成员所需内存空间的总和
多个同类对象共用同一个函数,内存中只需要保存一份函数代码
对象函数成员编译时,编译器会给函数成员的函数头添加对象指针作为形参  类名* const this



2.对象的构造和析构
变量在内存的生存期
       全局变量:静态分配的,程序开始立即分配,结束结束时释放
       局部变量:动态分配的,定义的代码块内生效
       静态变量:静态分配的,程序开始立即分配,结束结束时释放
对象:全局对象,局部对象,静态对象
      创建对象的过程称为对象的构造,销毁对象的过程称为析构。
      构造个性化对象:初始化对象,申请额外的内存。
      销毁个性化内存:释放额外申请的内存
构造函数:构造函数在被创建时自动调用,每创建一个对象,构造函数被调用一次。
                  – 构造函数名必须与类名相同。
                  – 构造函数由计算机自动调用,程序员不能直接调用。
                  – 构造函数通过形参传递初始值(可指定默认形参值),实现对新建对象数据成员的初始化。
                  – 构造函数可以重载,即定义多个同名的构造函数,这样可提供多种形式的对象构造方法。
                  – 构造函数可以定义成内联函数。(定义在声明处)
                  – 构造函数没有返回值,定义时不能写函数类型,写void也不行。
                  – 构造函数通常是类外调用,其访问权限应设为public或protected,不能设为private。
                  – 一个类如果没有定义构造函数,编译器在编译时将自动添加一个空的构造函数,称为默认构造函数,
                     其形式为:类名( ) { }
构造函数初始化对象:
Circle :: Circle( double x ) // 带形参的构造函数
{ r = x; }
Circle :: Circle( ) // 不带形参的构造函数
{ r = 0; }
Circle obj( 5.0 );	//引用第一个
Circle obj;		//引用第二个
Circle :: Circle( double x = 0 )
{ r = x; }
用已存在的对象初始化当前的新对象,称为拷贝构造函数:
Circle :: Circle( Circle &obj )	//引用
{ r = obj.r; }
Circle obj1( 5.0 );
Circle obj2( obj1 );

构造函数申请内存:
Student(char *pName, char *pID, int iniAge, double iniScore, char *pMemo)
{
strcpy(Name, pName); strcpy(ID, pID); // 初始化姓名、学号,对象字符串成员的相互赋值需使用strcpy
Age = iniAge; Score = iniScore; // 初始化年龄、成绩
int len = strlen( pMemo ); // 计算实际传递来的备注信息长度
if (len <= 0) Memo = 0; // 没有备注信息。 0表示空指针
else
{
Memo = new char[len +1]; // 按照实际长度分配内存
strcpy(Memo, pMemo); // 初始化备注信息
}
}
Student obj( “张三”, “1400500001”, 19, 95, “” );
Student obj( “张三”, “1400500001”, 19, 95, “市级三好学生” );
析构函数:
 – 析构函数名必须为“~类名”。
 – 析构函数由计算机自动调用,程序员不能直接调用。
 – 析构函数没有形参。
 – 析构函数没有返回值,定义时不能写函数类型,写void也不行。
 – 一个类只能有一个析构函数。
 – 析构函数通常是类外调用,其访问权限应设为public或protected,不能设为private。
 – 一个类如果没有定义析构函数,编译器在编译时将自动添加一个空的析构函数,称为默认析构函数,其形式为:~类名( ) { }
析构函数
 – 清理内存
 – 设置与当前对象相关的系统状态
~Student( )
{
if (Memo != 0) delete [ ]Memo;
}
拷贝构造函数的深拷贝和浅拷贝

Student(char *pName, char *pID, int iniAge, double iniScore, char *pMemo)
{
strcpy(Name, pName); strcpy(ID, pID); // 初始化姓名、学号,对象字符串成员的相互赋值需使用strcpy,strcpy与=的区别
Age = iniAge; Score = iniScore; // 初始化年龄、成绩
int len = strlen( pMemo ); // 计算实际传递来的备注信息长度
if (len <= 0) Memo = 0; // 没有备注信息。 0表示空指针
else
{
Memo = new char[len +1]; // 按照实际长度分配内存
strcpy(Memo, pMemo); // 初始化备注信息
}
}

Student obj1( “张三”, “1400500001”, 19, 95, “市级三好学生” );
Student obj2( obj1 ); // 将自动调用默认拷贝构造函数
//默认的拷贝构造函数
Student( Student &obj )
{
strcpy(Name, obj.Name); strcpy(ID, obj.ID); // 拷贝姓名、学号
Age = obj.Age; Score = obj.Score; // 拷贝年龄、成绩
Memo = obj.Memo; // 拷贝备注信息指针,注:并没有再分配内存
}
深拷贝:需要自定义拷贝构造函数(析构释放)
Student( Student &obj )
{
strcpy(Name, obj.Name); strcpy(ID, obj.ID); // 拷贝姓名、学号
Age = obj.Age; Score = obj.Score; // 拷贝年龄、成绩
// Memo = obj.Memo; // 拷贝备注信息指针,注:并没有再分配内存
int len = strlen( obj.Memo ); // 计算obj所引用对象的备注信息长度
if (len <= 0) Memo = 0; // 没有备注信息。 0表示空指针
else
{
Memo = new char[len +1]; // 按照实际长度分配内存(需加1个结束符’\0’)
strcpy(Memo, obj.Memo); // 拷贝obj所引用对象的备注信息
}
}

定义对象:
class Student // 定义一个学生信息类Student
{
public:
int Age; // 保存年龄的int型数据成员Age
double Score; // 保存成绩的double型数据成员Score
Student() // 内联构造函数
{
age = 0; // 初始化nianling
Score = 0.0;
}
};
定义对象:
Student student1;
Student *student = new Student();
//不可以用
Student student(a,b);
Student student2(student1);		//拷贝
obj.fun()会被编译成fun(&obj)


最后当类成员中有指针成员时,要添加拷贝构造函数。















### C++ 中构造函数、函数、赋值运算符拷贝构造函数 #### 构造函数 构造函数是一种特殊的方法,其名称与类名相同,在创建对象时由编译器自动调用。此方法用于初始化新创建的对象成员变量。如果程序员不提供任何构造函数,则编译器会生成一个默认版本[^3]。 ```cpp class MyClass { public: int value; // 默认构造函数 MyClass() : value(0) {} // 带参数的构造函数 MyClass(int v) : value(v) {} }; ``` #### 函数 函数负责清理工作,当对象的生命期结束时被自动调用。它没有参数也没有返回类型,并且在一个类中只能存在唯一的一个函数。如果没有显式定义,系统也会自动生成默认的函数[^2]。 ```cpp class MyClass { public: ~MyClass() { /* 清理资源 */ } }; ``` #### 拷贝构造函数 当通过已有的对象来创建另一个同类型的对象时,将会调用拷贝构造函数。这通常发生在传递或返回对象副本的情况下。为了防止浅复制带来的潜在问题(比如两个对象共享同一指针),应该实现深复制逻辑[^1]。 ```cpp class MyClass { private: char* data; public: // 拷贝构造函数 MyClass(const MyClass& other) { size_t len = strlen(other.data); data = new char[len + 1]; strcpy(data, other.data); } // 防止内存泄漏 ~MyClass() { delete[] data; } }; ``` #### 赋值运算符重载 对于已经存在的对象之间的赋值操作,默认情况下是按位逐字节复制。然而,这种行为可能导致意外的结果特别是涉及到动态分配的数据结时。因此建议重载 `operator=` 来确保安全有效的赋值过程。 ```cpp class MyClass { private: char* data; public: // 赋值运算符重载 MyClass& operator=(const MyClass& rhs) { if (this != &rhs) { delete[] this->data; size_t len = strlen(rhs.data); this->data = new char[len + 1]; strcpy(this->data, rhs.data); } return *this; } }; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值