1. 类与对象的编译原理
每个对象所占用的内存空间都等于类中全部数据成员所需内存空间的总和
多个同类对象共用同一个函数,内存中只需要保存一份函数代码
对象函数成员编译时,编译器会给函数成员的函数头添加对象指针作为形参 类名* const this
每个对象所占用的内存空间都等于类中全部数据成员所需内存空间的总和
多个同类对象共用同一个函数,内存中只需要保存一份函数代码
对象函数成员编译时,编译器会给函数成员的函数头添加对象指针作为形参 类名* const this
2.对象的构造和析构
变量在内存的生存期
全局变量:静态分配的,程序开始立即分配,结束结束时释放
局部变量:动态分配的,定义的代码块内生效
静态变量:静态分配的,程序开始立即分配,结束结束时释放
对象:全局对象,局部对象,静态对象
创建对象的过程称为对象的构造,销毁对象的过程称为析构。
构造个性化对象:初始化对象,申请额外的内存。
销毁个性化内存:释放额外申请的内存
构造函数:构造函数在被创建时自动调用,每创建一个对象,构造函数被调用一次。
– 构造函数名必须与类名相同。
– 构造函数由计算机自动调用,程序员不能直接调用。
– 构造函数通过形参传递初始值(可指定默认形参值),实现对新建对象数据成员的初始化。
– 构造函数可以重载,即定义多个同名的构造函数,这样可提供多种形式的对象构造方法。
– 构造函数可以定义成内联函数。(定义在声明处)
– 构造函数没有返回值,定义时不能写函数类型,写void也不行。
– 构造函数通常是类外调用,其访问权限应设为public或protected,不能设为private。
– 一个类如果没有定义构造函数,编译器在编译时将自动添加一个空的构造函数,称为默认构造函数,
其形式为:类名( ) { }
构造函数初始化对象:
变量在内存的生存期
全局变量:静态分配的,程序开始立即分配,结束结束时释放
局部变量:动态分配的,定义的代码块内生效
静态变量:静态分配的,程序开始立即分配,结束结束时释放
对象:全局对象,局部对象,静态对象
创建对象的过程称为对象的构造,销毁对象的过程称为析构。
构造个性化对象:初始化对象,申请额外的内存。
销毁个性化内存:释放额外申请的内存
构造函数:构造函数在被创建时自动调用,每创建一个对象,构造函数被调用一次。
– 构造函数名必须与类名相同。
– 构造函数由计算机自动调用,程序员不能直接调用。
– 构造函数通过形参传递初始值(可指定默认形参值),实现对新建对象数据成员的初始化。
– 构造函数可以重载,即定义多个同名的构造函数,这样可提供多种形式的对象构造方法。
– 构造函数可以定义成内联函数。(定义在声明处)
– 构造函数没有返回值,定义时不能写函数类型,写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。
– 一个类如果没有定义析构函数,编译器在编译时将自动添加一个空的析构函数,称为默认析构函数,其形式为:~类名( ) { }
– 析构函数名必须为“~类名”。
– 析构函数由计算机自动调用,程序员不能直接调用。
– 析构函数没有形参。
– 析构函数没有返回值,定义时不能写函数类型,写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所引用对象的备注信息
}
}
定义对象:
{
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)
最后当类成员中有指针成员时,要添加拷贝构造函数。