2018春节放假安排 网站建设,岳阳网站设计u,pycharm 网站开发,莱芜在线董事长对象的生离死别
实验介绍 在构建一个类时#xff0c;一般情况下需要编写构造函数、拷贝构造函数以及析构函数#xff0c;这将直接影响程序的运行。而初始化列表是在调用构造函数时初始化参数的方式。 一个对象从实例化到销毁的历程#xff1a; 知识点
内存分区构造函数exp…对象的生离死别
实验介绍 在构建一个类时一般情况下需要编写构造函数、拷贝构造函数以及析构函数这将直接影响程序的运行。而初始化列表是在调用构造函数时初始化参数的方式。 一个对象从实例化到销毁的历程 知识点
内存分区构造函数explicit 关键字初始化列表拷贝构造函数析构函数
内存分区
介绍 根据存储数据的类型系统将不同类型的数据存储在不同的区域作为 C 开发者必须对内存的分区以及使用了然于心。 分区
一般情况下根据内存用途将内存划分为五个区
内存区用途解释栈区存储函数的参数、局部变量等堆区由程序员分配、释放内存全局区存储全局变量和静态变量常量区存储常量代码区存储逻辑代码的二进制
栈与堆对比
功能栈堆申请与释放编译器自动分配、回收程序员分配和释放C 使用 malloc 申请内存、free 释放内存C 使用 new 申请内存、delete 释放内存申请内存后系统的响应申请空间大于栈空间时程序将提示异常 (栈溢出)超过内存空间程序报异常空间大小限制window 1 M / linux 8 M系统内存比栈大很多申请效率快比较慢只是相对栈实际也很快
示例代码 1
#include iostream
using namespace std;class Plan
{// 默认为私有属性int wingCount;
public:// 代码区Plan() { wingCount 0; }~Plan() {}int getWingCount() { return wingCount; }
};int main()
{// 栈上Plan p1;Plan p2;Plan p3;p1.getWingCount();p2.getWingCount();p3.getWingCount();return 0;
}
代码解释
编译时 getWingCount 只存储一份。实例化的对象 p1、p2、p3 存储在栈上。当对象调用 getWingCount 成员函数只需要找到相应地址即可。当变量没有被初始化时是一个随机值建议所有变量都初始化。示例代码 1 中数据在类默认私有属性区域但一般建议添加封装属性关键字。
构造函数 定义构造函数又称构造方法、建构子、构造器是类里用于创建对象的特殊子程序。可以初始化一个新建的对象并时常接受参数用以设定实例变量。 规则与特点
对象实例化时自动被调用。与类名同名。没有返回值。可以有多个重载形式。实例化对象时仅用到一个构造函数。当用户没有定义构造函数时编译器自动生成。
示例代码 2
#include iostream
#include string
using namespace std;class Teacher
{
public:// 1. 无参构造函数Teacher() {}// 2. 有参构造函数Teacher(string name, int age) {this-name name;this-age age;}// 3. 有参构造函数--全部有默认参数--默认构造函数/*Teacher(string name jake, int age 15) {this-name name;this-age age;}*/
private:string name;int age;
};
注意
根据重载函数的规则例如示例代码 2 中有参构造函数与缺省构造函数不能同时使用因为参数的个数和类型都是相同的。示例代码 2 中无参构造函数与缺省构造函数也不能同时使用因为编译器无法识别是使用无参构造函数还是使用缺省函数。如果实例化对象不需要传递参数的构造函数统称默认构造函数。
explicit 关键字 作用指定构造函数或转换函数或推导指引为显示即不能用于隐式转换赋值初始化。默认情况下类构造函数为 implicit隐式。 在讲解构造函数时需要提到 explicit 关键字因为很多时候会使用到 explicit 关键字。
示例代码 3
#include iostream
#include string
using namespace std;class A
{
public:// 默认 implicit隐式转换A(int) { } // 转换构造函数A(int, int) { } // 转换构造函数 (C11)operator bool() const { return true; }
};class B
{
public:// 申明构造函数使用显示声明不能隐式转换explicit B(int) { }explicit B(int, int) { }explicit operator bool() const { return true; }
};int main()
{A a1 1; // OK赋值初始化选择 A::A(int)A a2(2); // OK直接初始化选择 A::A(int)A a3 {4, 5}; // OK直接列表初始化选择 A::A(int, int)A a4 {4, 5}; // OK赋值列表初始化选择 A::A(int, int)A a5 (A)1; // OK显式转型进行 static_castif (a1) ; // OKA::operator bool()bool na1 a1; // OK赋值初始化选择 A::operator bool()bool na2 static_castbool(a1); // OKstatic_cast 进行直接初始化// B b1 1; // err赋值初始化不考虑 B::B(int)B b2(2); // OK直接初始化选择 B::B(int)B b3 {4, 5}; // OK直接列表初始化选择 B::B(int, int)
// B b4 {4, 5}; // err赋值列表初始化不考虑 B::B(int,int)B b5 (B)1; // OK显式转型进行 static_castif (b2) ; // OKB::operator bool()
// bool nb1 b2; // err赋值初始化不考虑 B::operator bool()bool nb2 static_castbool(b2); // OKstatic_cast 进行直接初始化
}
防赋值初始化时使用 explicit 关键字防赋值列表初始化时使用 explicit 关键字
拷贝构造函数
语法格式类名(const 类名 变量)。如果没有自定义构造函数系统自动生成。采用直接初始化或赋值初始化实例化对象时系统自动调用拷贝构造函数。
示例代码 4
#include iostream
#include string
using namespace std;class Teacher
{
public:// 1. 无参构造函数Teacher() {}// 2. 有参构造函数Teacher(string name, int age) {this-name name;this-age age;}// 3. 拷贝构造函数Teacher(const Teacher tea) {this-name tea.name;this-age tea.age;}
private:string name;int age;
};int main()
{// 执行默认构造函数Teacher tea1;// 执行拷贝构造函数Teacher tea2 tea1;Teacher tea3 Teacher(tea1);return 0;
}
注意
拷贝构造函数也是构造函数的一种当执行了拷贝构造函数后就不会执行其他构造函数。如果不涉及深拷贝可以不实现拷贝默认构造函数使用系统自动生成的拷贝构造函数即可。
初始化列表
先于构造函数执行。只能用于构造函数。可以同时初始化多个数据成员多个数据成员之间使用逗号隔开。
示例代码 5
#include iostream
using namespace std;class Circle
{
public:Circle() : Pi(3.14) {}// 错误Circle() { Pi 3.14; }
private:const double Pi;
};
注意
语法格式类名() : 数据成员 1(参数), 数据成员 2(参数) {}。由于初始化列表先于构造函数执行当类中有 const 常量时就必须要用到初始化列表来初始化。推荐使用初始化列表的方式来初始化数据成员。如果类中有数据成员时推荐将数据成员都初始化。
析构函数
析构函数是在对象销毁时自动调用的函数一般将释放内存的工作放在析构函数中完成。
语法格式~类名()。析构函数不允许有任何参数、不允许重载、没有返回值。如果没有自定析构函数系统自动生成。对象销毁时自动调用。
示例代码 6
#include iostream
using namespace std;class Student
{
public:Student() : buffer(new char[16]) {}~Student() {// 析构函数释放内存delete [] buffer;buffer nullptr;}
private:char *buffer;
};
实验总结
类定义要素
一个好的构造函数、拷贝构造函数和析构函数可以使程序使用更加稳健。在编写构造函数时需要考虑是否使用 explicit 关键字修饰。推荐在编写程序时使用初始化列表的方式初始化参数。析构函数时要注意释放堆中的内存但也要注意避免重复释放内存造成程序崩溃。