欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++面向对象——构造函数与析构函数、内存分区模型

程序员文章站 2024-03-17 16:26:04
...

目录

目录

构造函数

构造函数的三种方法

初始化列表

拷贝构造函数

浅拷贝与深拷贝

类对象作为其他类对象的成员变量

诸多注意事项

析构函数

内存分区模型

析构函数



构造函数

构造函数的三种方法

1.括号法(常用)

????:

student stu01(”张三”,190110101);
student stu02(stu01);

2.显式法

????:

student stu01 = student(”张三”,190110101);
student stu02 = student(stu01);
//匿名对象
student(”张三”,190110101);

特点:当前行执行结束后,系统立即回收匿名对象

不要利用拷贝构造函数初始化匿名对象

编译器会认为 student(stu02) === student stu02; 这是对象声明

3.隐式转换法

????:

student stu01 = 100;
student stu02 = stu01;

初始化列表

1.尽量使用初始化列表来初始化类

2.理由:使用构造函数时是先赋值再初始化,使用初始化列表可以直接完成初始化

3.类A做类B的成员变量时,应用初始化变量初始化类A,而非构造函数

4.不可对静态成员变量初始化列表,只能在类外定义时初始化

拷贝构造函数

1.拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。

2.拷贝构造函数通常用于:

(1)通过使用另一个同类型的对象来初始化新创建的对象。

(2)复制对象把它作为参数传递给函数。

(3)复制对象,并从函数返回这个对象。

3.拷贝构造函数的形式:
 

classname(const classname &obj)
{
//statement
}

注意事项

(1)不改变本体,加const

(2)对象前加引用符号&

????:

Line (int len);
Line (const Line &obj);

obj是一个对象引用,该对象是用于初始化另一个对象。

4.构造实例:注意类中带有指针变量,并有动态内存分配时的做法。(截自菜鸟教程——C++拷贝构造函数

C++面向对象——构造函数与析构函数、内存分区模型

5.当定义一个新对象并用一个同类型的对象对它进行初始化时,将显示使用拷贝构造函数。当该类型的对象传递给函数或从函数返回该类型的对象时,将隐式调用拷贝构造函数。

6.什么情况使用拷贝构造函数:

类的对象需要拷贝时,拷贝构造函数将会被调用。

浅拷贝与深拷贝

1.简单的赋值拷贝使用浅拷贝

2.成员变量含指针时使用深拷贝

定义类时使用:

private:
string  *name;

此时使用深拷贝得到的name指向地址不同

拷贝构造函数中使用:

m_Name = new string (*name);

析构函数中使用:

if ( m_Name != NULL ){
delete m_Name;
m_Name = NULL;
}

使用if判断语句而不是直接delete或不是使用默认析构的原因是防止堆区内存重复释放

类对象作为其他类对象的成员变量

1.类中如果需要其他对象作为私有变量或者protected时,只能调用没有参数的构造函数。

2.若想在类中调用其它类的对象且带有参数的构造函数时,只能将其放入成员函数里对其进行调用。

诸多注意事项

1.构造函数的重载规则与普通函数的重载规则相同。

2.初始化参数列表的方法:
 

Student :: Student (string name,string desc)
               : m_Name(name) , m_desc(desc)

注意:形参名与下方括号内名相同

3.拷贝构造函数调用时机:

(1)使用一个已经创建完毕的对象来初始化一个新对象

(2)值传递的方式给函数参数传值,即类对象做形参

(3)以值方式返回局部对象

????:

student test01()
{
student stu01;
return stu01;
}
void test02()
{
student stu02 = test01();
}

4.为避免初始化列表时出现错误,建议如下:

(1)总是按照你希望它们被初始化的顺序声明成员。

(2)总是按照它们声明的顺序罗列这些成员。

6.调用默认构造函数时不要加()

????:student stu01();     //错误!编译器认为这是一个返回student的无参函数

7.写了有参构造函数后编译器不再提供默认构造函数,此时若不写默认构造函数,书写以下代码会报错:

student stu01;

8.写了拷贝构造后编译器不再提供默认构造,也无带参构造

1.栈内存存放基本类型的变量,栈内数据存储速度快,但存储量不大。

 

2.堆内存存放动态申请的数据,全局变量,*度高,灵活。

析构函数

内存分区模型

1.C++程序执行将内存大致分为四区域

(1)代码区:存储函数体的二进制代码,由操作系统进行管理。

(2)全局区:存放全局变量,静态变量和常量。

(3)栈区:由编译器自动分配释放,存放函数的参数值,局部变量等

(4)堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

2.程序运行前:

程序编译后,生成了exe可执行程序,未执行程序前分为两个区域

(1)代码区:

存放CPU执行的机器指令,分为共享与只读

共享的目的是对于频繁被执行的程序,只需在内存中有一份代码即可

只读的目的是防止程序意外地修改其指令

(2)全局区:

全局变量和静态变量存放于此

全局区还包含了常量区,字符串常量和其他常量(如const常量)也存放于此

该区域的数据在程序结束后由操作系统释放

3.程序运行后

(1)栈区

不要返回局部变量的地址,栈区的数据在函数执行完成后自动释放

形参数据也会放在栈区

(2)堆区

由程序员分配释放,若程序员不释放,程序结束时由操作系统回收

在C++中主要利用new在堆区开辟内存

????:

int *p = new int(10);
int *arr = new int[10];

利用new开辟一块新内存

利用指针p指向改内存

指针变量p本身在栈区

不要忘记在后面加上:

delete p;
delete[] arr;     //注意释放数组内存的方法

此时再访问p所指内存即是非法操作

析构函数

1.对象过期时自动调用的特殊成员函数。

2.析构函数一般用来完成清理工作。

3.析构函数的名称是在类名前加~

4.析构函数没有参数,且只能有一个析构函数。

5.析构函数用来释放对象使用的资源,并销毁对象的非static数据成员。

6.无论何时一个对象被销毁,都会自动调用其析构函数(隐式析构)

7.(笔记写了很久自己也忘记这个截自哪里了...)

C++面向对象——构造函数与析构函数、内存分区模型

8.在栈内存申请的空间在使用后会被自动释放,而在堆内存申请的空间(动态内存分配)则必须手动释放。

????:
 

Student* stu5 = new Student(”Jack”,”Jacky”);
// processing
delete stu5;

9. 实战时多使用堆内存,少使用栈内存。