纯虚函数和抽象类

什么是纯虚函数

纯虚函数是一种特殊的虚函数,前面分析过虚函数,虚函数是virtual修饰的类的成员函数,可以有实现。而纯虚函数也和虚函数一样,用virtual来修饰的类的成员函数,但是只能有函数体不能有具体实现

一般格式:

class <类名>
{
    virtual <类型><函数名>(<参数表>) = 0;
    ...
}

1、纯虚函数是一个在父类中只有函数体,没有实现,实现在子类中去完成

2、纯虚函数为各子类提供了一个公共界面(接口的封装和设计、软件的模块功能划分)

3、一个具有纯虚函数的父类也称为抽象类

为什么要用到纯虚函数(抽象类)

1、为了方便使用多态特性

2、在很多情况下,父类本身生成对象是不合理的。例如,动物作为一个父类可以派生出猫、狗等子类,但动物本身生成对象明显不合理。

#pragma warning(disable : 4996)
#include <iostream>
using namespace std;

class Animal
{
public:
    Animal() 
    {
        this->m_a = 1;
        cout << "Animal: 构造函数" << endl;
    }
    ~Animal() {}
    virtual void Call()
    {
        cout << "Animal: Call" << endl;
    }
    virtual void Eat() = 0;
private:
    int m_a;
};

class Cat:public Animal
{
public:
    Cat() 
    {
        this->m_a = 2;
        cout << "Cat: 构造函数" << endl;
    }
    ~Cat() {}
    virtual void Call()
    {
        cout << "Cat: Call" << endl;
    }
    void Eat()
    {
        cout << "Cat: Eat" << endl;
    }
private:
    int m_a;
};

//不允许使用抽象类作函数参数
//void Test(Animal a){}

int main()
{
    //Animal a1;//不允许使用抽象类类型
    //Animal a2();//不允许返回抽象类
    //Test(a1);//不允许使用抽象类作函数参数

    Animal *a = new Cat();
    a->Call();
    a->Eat();

    Cat c;
    Animal &a1 = c;
    a1.Call();
    a1.Eat();

    printf("父类占内存大小:%d, 子类占内存大小:%d\n", sizeof(Animal), sizeof(Cat));
    system("pause");
    return 0;
}

如上面的例子,我们可以总结对抽象类做哪些操作是合理的:

1、可以声明抽象类的指针:Animal *cat = new Cat();

2、可以声明抽象类的引用:Animal &cat

抽象类在多继承中的应用

C++中没有接口这个概念,学过其他高级语言的朋友可能接触过了接口(协议)这个概念,那么C++中的抽象类就是模拟的这种机制。但是在继承中高级语言不能继承多个父类,可以继承多个接口,C++中没有接口这个概念,但可以继承多个类,那就是多继承概念。

绝大多数面向对象语言都不支持多继承,绝大多数面向对象语言都支持接口的概念,C++中没有接口的概念,C++中可以使用纯虚函数实现接口,接口类中只有函数原型定义,没有任何数据的定义

class Interface1
{
public:
    virtual void print() = 0;
    virtual int add(int a, int b) = 0;
};

class Interface2
{
public:
    virtual void print() = 0;
    virtual int add(int a, int b) = 0;
    virtual int minus(int a, int b) = 0;
};

class parent
{
public:
    int a;
};

class Child : public parent, public Interface1, public Interface2
{
public:
    void print()
    {
        cout << "Child::print" << endl;
    }
    int add(int a, int b)
    {
        return a + b;
    }
    int minus(int a, int b)
    {
        return a - b;
    }
};

int main()
{
    Child c;
    c.print();

    cout << c.add(3, 5) << endl;
    cout << c.minus(4, 6) << endl;

    Interface1* i1 = &c;
    Interface2* i2 = &c;

    cout << i1->add(7, 8) << endl;
    cout << i2->add(7, 8) << endl;

    system("pause");
    return 0;
}

由上面的例子可以得出:

  • 多重继承接口不会带来二义性和复杂性等问题  
  • 多重继承可以通过精心设计用单继承和接口来代替
  • 接口类只是一个功能说明,而不是功能实现。
  • 子类需要根据功能说明定义功能实现。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值