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

目录

目录

构造函数

构造函数的三种方法

初始化列表

拷贝构造函数

浅拷贝与深拷贝

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

诸多注意事项

析构函数

内存分区模型

析构函数



构造函数

构造函数的三种方法

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++面向对象——构造函数与析构函数、内存分区模型_第1张图片

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++面向对象——构造函数与析构函数、内存分区模型_第2张图片

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


 

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

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

你可能感兴趣的:(C++,c++,面向对象编程)