主要学习内容
一、C++析构函数
- 析构函数的特征
(1)没有返回值 (2)函数名是在类名前面加~符号。 (3)和构造函数一样,也是一种特殊的成员函数,不需要程序员显示调用。 (4)析构函数没有参数,不能被重载,因此一个类只能有一个析构函数;如果用户没有定义,编译器会自动生成一个默认的析构函数。 注意: a.析构函数一般是在销毁对象时自动调用的,比如释放分配的内存、关闭打开的文件。 b. 析构函数唯一的作用就是给删除的对象后释放已经分配的内存。
#include <iostream>
using namespace std;
class Demo{
public:
Demo(int len);
~Demo();
void input();
void show();
private:
const int m_len;
int *m_arr;
int *m_p;
int* parri(int i);
};
Demo::Demo(int len):m_len(len){
if(len > 0)
{
m_arr = new int[len];
}
else
{
m_arr = NULL;
}
}
Demo::~Demo(){
delete[] m_arr;
}
int* Demo::parri(int i){
if(!m_arr || i < 0 || i >= m_len)
{
return NULL;
}
else
{
return m_arr + i;
}
}
void Demo::input(){
for(int i = 0; m_p = parri(i); i++)
{
cin>>*parri(i);
}
}
void Demo::show(){
for(int i = 0; m_p = parri(i); i++)
{
if(i == m_len -1)
{
cout<<*parri(i)<<endl;
}
else
{
cout<<*parri(i)<<",";
}
}
}
int main()
{
int n;
cout<<"请输入数组的长度:";
cin>>n;
Demo *parr = new Demo(n);
cout<<"Input "<<"n"<<"number:";
parr->input();
cout<<"数组的元素有:";
parr->show();
delete parr;
return 0;
}
输出结果: 注意: a.在函数内部创建的对象是局部对象,它和局部变量类似,位于栈区,函数执行结束时会调用这些对象的析构函数。 b. new 创建的对象位于堆区,通过 delete 删除时才会调用析构函数;如果没有 delete,析构函数就不会被执行。
二、C++中的对象数组
对象数组:就是数组的每个元素都是一个对象。 既然是对象,那么数组中的每个元素都需要用构造函数进行初始化。具体如何调用哪个构造函数,看下面的示例:
#include <iostream>
using namespace std;
class Demo{
public:
Demo(){
cout<<"called func1"<<endl;
}
Demo(int n){
cout<<"called func2"<<endl;
}
};
int main()
{
cout<<"step1"<<endl;
Demo arr[2];
cout<<"step2"<<endl;
Demo arr2[2]={3,6};
cout<<"step3"<<endl;
Demo arr3[2] = {4};
cout<<"step4"<<endl;
Demo *arr4 = new Demo[2];
delete[] arr4;
return 0;
}
输出结果:
三、C++中的成员对象
成员对象:一个类的成员变量如果是另一个类的对象,就称之为“成员对象”。 包含成员对象的类叫封闭类(enclosed class)。
#include <iostream>
using namespace std;
class Type{
public:
Type(int year, int page):m_year(year),m_page(page){};
void show() const;
private:
int m_year;
int m_page;
};
class Book{
public:
Book(int price, int year, int page):m_price(price),m_info(year,page){
};
void show() const;
private:
int m_price;
Type m_info;
};
void Type::show() const{
cout<<"出版年份:"<<m_year<<endl;
cout<<"该数的总页数:"<<m_page<<endl;
}
void Book::show()const{
cout<<"价格:"<<this->m_price<<"$"<<endl;
this->m_info.show();
}
int main()
{
Book newbook(20,2006,344);
newbook.show();
return 0;
}
运行结果: 注意: a. 生成封闭类对象的语句一定要让编译器能够弄明白其成员对象是如何初始化的,否则就会编译错误。
#include <iostream>
using namespace std;
class Paper{
public:
Paper(){
cout<<"调用顺序2"<<endl;
}
~Paper(){
cout<<"调用顺序5"<<endl;
}
};
class Book{
public:
Book(){
cout<<"调用顺序1"<<endl;
}
~Book(){
cout<<"调用顺序6"<<endl;
}
};
class Shop{
public:
Shop(){
cout<<"调用顺序3"<<endl;
}
~Shop(){
cout<<"调用顺序4"<<endl;
}
private:
Book newbook;
Paper newpaper;
};
int main()
{
Shop newshop;
return 0;
}
运行结果:
注意: a. 封闭类对象生成时,先执行所有成员对象的构造函数,然后才执行封闭类自己的构造函数。 b. 成员对象构造函数的执行次序和成员对象在类定义中的次序一致,与它们在构造函数初始化列表中出现的次序无关。 比如:上面的例子中Shop类中先后定义了Book和Paper类的对象,由定义决定先后调用哪个类的构造函数初始化。 c. 当封闭类对象消亡时,先执行封闭类(先Shop类)的析构函数,然后再执行成员对象(paper和newbook)的析构函数。
|