C++系列-纯虚函数,抽象类,虚析构和纯虚析构

纯虚函数,抽象类,虚析构和纯虚析构


归园田居(其一)
陶渊明 魏晋

少无适俗韵,性本爱丘山。误落尘网中,一去三十年。

羁鸟恋旧林,池鱼思故渊。开荒南野际,守拙归园田。

方宅十余亩,草屋八九间。榆柳荫后檐,桃李罗堂前。

暧暧远人村,依依墟里烟。狗吠深巷中,鸡鸣桑树颠。

户庭无尘杂,虚室有余闲。久在樊笼里,复得返自然。


纯虚函数

在多态中,子类会重写父类中的虚函数,用于实现多态。通常父类中的虚函数是无意义的,一般不用。实际中主要是调用子类重写的内容,可以使用纯虚函数
纯虚函数:

  • virtual 返回类型 函数名(参数列表)=0, 这样的函数为纯虚函数。

抽象类

抽象类:当类中有了纯虚函数,则类称为抽象类。

抽象类的特点

  • 无法实例化对象。
  • 抽象类的子类必须重写抽象类中的纯虚函数,否则也属于抽象类(没重写的话,完全是继承父类的纯虚函数)

抽象类的举例

code: 
// 父类是抽象类,无法实例化对象, 子类Taro没有重写父类的纯虚函数,也是抽象类,无法实例化对象。
#include <iostream>
using namespace std;

class Vegetable
{
public:
	virtual void eat() = 0; //纯虚函数
};
class Spinach : public Vegetable
{
public:
	void eat()
	{
		cout << "多吃 菠菜 对身体好哦!" << endl;
	}
};

class Taro : public Vegetable
{
};

int main()
{
	// Vegetable veg1;		// 抽象类无法实例化对象
	Spinach sp1;			
	sp1.eat();		
	Vegetable* veg2 = new Spinach;	// 多态的使用
	veg2->eat();
	delete veg2;
	// Taro ta1;			// 抽象类无法实例化对象
	system("pause");
	return 0;
}

result:
多吃 菠菜 对身体好哦!
多吃 菠菜 对身体好哦!
#include <iostream>
using namespace std;

// 抽象父类,纯虚函数,不改变现有的其它结构,其它再有类似的饮料制作方法,直接后面再增加类,实现具体方法即可
class Beverage
{
public:
    virtual void boil() = 0 {}

    virtual void brew() = 0 {}

    virtual void add_additive() = 0 {}

    virtual void pour() = 0 {}
    
    void make_beverage()
    {
        boil();
        brew();
        add_additive();
        pour();
    }
};

class Tea : public Beverage
{
public:
    virtual void boil()
    {
        cout << "煮烧泠泠水" << endl;
    }
    virtual void brew()
    {
        cout << "冲泡瑟瑟尘" << endl;
    }
    virtual void add_additive()
    {
        cout << "添就茉莉香" << endl;
    }
    virtual void pour()
    {
        cout << "寄与爱茶人" << endl;
    }
};


class Coffee : public Beverage
{
public:
    virtual void boil()
    {
        cout << "煮自来水" << endl;
    }
    virtual void brew()
    {
        cout << "冲泡咖啡" << endl;
    }
    virtual void add_additive()
    {
        cout << "加植脂末等材料" << endl;
    }
    virtual void pour()
    {
        cout << "倒入杯中" << endl;
    }
};

int main()
{
    Beverage* bev1;      // 父类指针
    int choice;
    
    while (1)
    {
        cout << "------------ 请选择操作 ------------" << endl;
        cout << "1. 泡茶" << endl;
        cout << "2. 冲咖啡" << endl;
        cout << "0. 退出" << endl;
        cin >> choice;          //
        if (choice == 0)
        {
            cout << "退出过程" << endl;
            break;
        }
        else
        {
            switch (choice)
            {
            case 1:
                bev1 = new Tea();     // 父类指针指向子类对象
                break;
            case 2:
                bev1 = new Coffee();
                break;

            default:
                cout << "无效的选择" << endl;
                return 1;
            }
            bev1->make_beverage();
        }
        delete bev1;
    }
    system("pause");
    return 0;
}

虚析构

  • 多态应用中,如果子类中有属性开辟到堆区,那么父类指针或者引用在释放时无法调用到子类的析构代码(如果子类无析构函数),则会造成内存泄漏。
  • 将父类中的析构函数改为虚析构或者纯虚析构,在子类中实现自身的虚构函数,可以解决这个问题。
  • 需要有具体的函数实现(为了确保父类有析构代码执行)。
  • 如果子类中没有堆区数据,可以不写虚析构。

以下代码无法释放子类对象开辟在堆区的数据

code:
// 在delete父类指针指向的子类对象时,调用的是父类的析构函数,无法释放子类中开辟在堆区的数据
#include <iostream>
using namespace std;

class Vegetable
{
public:
	Vegetable()
	{
		cout << "Vegetable constructor" << endl;
	}
	virtual void eat() = 0; //纯虚函数
	~Vegetable()		
	{
		cout << "Vegetable destructor" << endl;
	}
};

class Spinach : public Vegetable
{
public:
	Spinach(string type)
	{
		cout << "Spinach constructor" << endl;
		m_type = new string(type);			// 创建在堆区
	}
	void eat()
	{
		cout << "Eating more " << * m_type << " spinach is good for health." << endl;
	}
	string *m_type;		
	
	~Spinach()
	{
		if (m_type != NULL)
		{
			cout << "Spinach destructor" << endl;
			delete m_type;
			m_type = NULL;
		}
	}
};

void test01()
{
	Vegetable* veg1 = new Spinach("organic");
	veg1->eat();
	// 父类指针在析构时候,不会调用子类中的析构函数,导致子类中如果有堆区数据,无法释放
	delete veg1;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

result:
Vegetable constructor
Spinach constructor
Eating more organic spinach is good for health.
Vegetable destructor

将父类的析构函数改为虚析构

code:
// 在delete父类指针指向的子类对象时,先调用的是子类虚构函数,然后调用父类的
#include <iostream>
using namespace std;

class Vegetable
{
public:
	Vegetable()
	{
		cout << "Vegetable constructor" << endl;
	}
	virtual void eat() = 0; //纯虚函数
	virtual ~Vegetable()		
	{
		cout << "Vegetable destructor" << endl;
	}
};

class Spinach : public Vegetable
{
public:
	Spinach(string type)
	{
		cout << "Spinach constructor" << endl;
		m_type = new string(type);			// 创建在堆区
	}
	void eat()
	{
		cout << "Eating more " << * m_type << " spinach is good for health." << endl;
	}
	string *m_type;		
	
	~Spinach()
	{
		if (m_type != NULL)
		{
			cout << "Spinach destructor" << endl;
			delete m_type;
			m_type = NULL;
		}
	}
};

void test01()
{
	Vegetable* veg1 = new Spinach("organic");
	veg1->eat();
	// 父类指针在析构时候,先会调用子类中的析构函数,然后调用父类的析构函数
	delete veg1;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

result:
Vegetable constructor
Spinach constructor
Eating more organic spinach is good for health.
Spinach destructor
Vegetable destructor

纯虚析构

虚析构和纯虚析构的特点:

  • 可以解决父类指针或引用释放子类对象时,子类对象的内存无法释放的问题。
  • 父类中的虚析构和纯虚析构需要有具体的函数实现。
  • 如果是纯虚函数,则类属于抽象类,无法实例化对象。
  • vitrual ~类名() {}
  • vitrual ~类名() = 0, 然后在类外实现, 类名:: ~类名() {}
  • 如果子类中没有堆区数据,可以不写虚析构。
code:
#include <iostream>
using namespace std;

class Vegetable
{
public:
	Vegetable()
	{
		cout << "Vegetable constructor" << endl;
	}
	virtual void eat() = 0; //纯虚函数
	virtual ~Vegetable() = 0;			// 纯虚析构函数需要有实现,因为如果有父类的一些数据需要释放,需要走析构函数的
};

Vegetable::~Vegetable()
{
	cout << "Vegetable pure destructor" << endl;
}


class Spinach : public Vegetable
{
public:
	Spinach(string type)
	{
		cout << "Spinach constructor" << endl;
		m_type = new string(type);			// 创建在堆区
	}
	void eat()
	{
		cout << "Eating more " << * m_type << " spinach is good for health." << endl;
	}
	string *m_type;		
	
	~Spinach()
	{
		if (m_type != NULL)
		{
			cout << "Spinach destructor" << endl;
			delete m_type;
			m_type = NULL;
		}
	}
};

void test01()
{
	Vegetable* veg1 = new Spinach("organic");
	veg1->eat();
	// 父类指针在析构时候,不会调用子类中的析构函数,导致子类中如果有堆区数据,无法释放
	delete veg1;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

result:
Vegetable constructor
Spinach constructor
Eating more organic spinach is good for health.
Spinach destructor
Vegetable destructor
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值