跳至主要內容

纯虚函数和抽象类

张威大约 4 分钟使用指南页面配置使用指南

纯虚函数和抽象类

纯虚函数

纯虚函数是一种特殊的虚函数。这就是纯虚函数的作用。纯虚函数的格式如下:

class 类名
{
public:
    virtual 返回类型 函数名(参数包) = 0;
};

设置纯虚函数的意义,就是让所有的类对象(主要是派生类对象)都可以执行纯虚函数的动作,但类无法为纯虚函数提供一个合理的缺省实现。所以类纯虚函数的声明就是在告诉子类的设计者,“你提供一个纯虚函数的实现,但我不知道你会怎样实现它”

class Base
{
public:
    virtual void display() = 0;
};
class Derived
: public Base 
{
public:
    virtual void display()
    {
        cout << "Derived::display()" << endl;
    }
};

声明纯虚函数的目的在于,提供一个与派生类

class Figure
{
public:
    virtual void display() const = 0;
    virtual double area() const = 0;
};
class Circle
: public Figure 
{
public:
    explicit Circle(double radius)
    : _radius(radius) 
    {
        
    }
    
    void display() const
    {   
        cout << "Circle";
    }
    
    double area() const 
    {   
        return 3.14159 * _radius * _radius;
    }
private:
    double _radius;
    };
class Rectangle
: public Figure 
{
public:
    Rectangle(double length, double width)
    : _length(length)
    , _width(width)
    {
        
    }
    
    void display() const
    {   
        cout << "Rectangle";    
    }
    
    double area() const
    {   
        return _length * _width;
    }
private:
    double _length;
    double _width;
};

class Triangle
: public Figure 
{
public:
    Triangle(double a, double b, double c)
    : _a(a)
    , _b(b)
    , _c(c)
    {
        
    }
    
    void display() const 
    {   
        cout << "Triangle"; 
    }
    
    //海伦公式计算三角形的面积
    double area() const 
    {   
        double p = (_a + _b + _c) / 2;
        return  sqrt(p * (p - _a) * (p - _b) * (p - _c));
    }    
private:
    double _a;
    double _b;
    double _c;
};

抽象类

抽象类的形式

  1. 类中包含纯虚函数

一个类可以包含纯虚函数。只要类中含有一个纯虚函数,该类便为抽象类

//汽车的基类,抽象类
class Car
{
public:
	Car(string name, double oil):_name(name),_oil(oil){}
	//获取汽车剩余油量还能跑的公里数
	double getLeftMiles()
	{
		//不同汽车1L油跑的公里不一样
		return _oil * this->getMilesPerGallon();//动态绑定,
		//基类指针指向不同派生类对象访问不同派生类重写的getMilesPerGallon()
	}
	string getName()const
	{
		return _name;
	}
protected:
	string _name;
	double _oil;
	virtual double getMilesPerGallon() = 0;//纯虚函数,根据具体的汽车而定1L油跑的公里数
};

class Bnze : public Car
{
public:
	Bnze(string name, double oil):Car(name, oil){}
	double getMilesPerGallon()
	{
		return 20.0;//具体的车跑到公里不一样
	}
};

class Audi : public Car
{
public:
	Audi(string name, double oil):Car(name, oil){}
	double getMilesPerGallon()
	{
		return 18.0;//具体的车跑到公里不一样
	}
};

class BMW : public Car
{
	public:
	BMW(string name, double oil):Car(name, oil){}
	double getMilesPerGallon()
	{
		return 19.0;//具体的车跑到公里不一样
	}
};

//给外部提供一个统一的获取汽车剩余路程数的API
void showCarleftMiles(Car &car)
{
	cout << car.getName() << "left miles:" << car.getLeftMiles() << "公里" << endl;
}

int main()
{
	Bnze b1("奔驰",20.0);
	Audi a("奥迪",20.0);
	BMW b2("宝马",20.0);
	showCarleftMiles(b1);
	showCarleftMiles(a);
	showCarleftMiles(b2);

	return 0;
}
  1. 继承纯虚函数,但没有重写

和普通的虚函数不同,在派生类中一般要对基类中纯虚函数进行重定义。如果该派生类没有对所有的纯虚函数进行重定义,则该派生类也会成为抽象类。这说明

  1. 只有protect构造没有public构造的类

除此以外,还有另外一种形式的抽象类。对一个类来说,如果只定义了protected型的构造函数而没有提供public构造函数,无论是在外部还是在派生类中作为其对象成员,但可以由其派生出新的类,这种能派生新类,却不能创建自己对象的类是另一种形式的抽象类

class Base 
{
protected:
    Base(long base)
    : _base(base)
    {   
        cout << "Base()" << endl;
    }  
protected:
    long _base;
};
class Derived
: public Base
{
public:
    Derived(long base, long derived)
    : Base(base)
    , _derived(derived)
    {
        cout << "Derived(long, long)" << endl;  
    }
    
    void print() const 
    {
        cout << "_base:" << _base
             << ", _derived:" << _derived << endl;
    }
private:
    long _derived;
};
void test()
{
    Base base(1);//error
    Derived derived(1, 2);
}

为什么定义抽象类?抽象类和普通类的区别

  1. 抽象类的目的不是为了抽象一个实体的类型,主要目的:

    1. 让所有的派生类类通过继承基类直接复用该属性。(猫具有动物属性)
    2. 给所有的派生类保留统一的覆盖/重写接口
  2. 语法上

    1. 拥有纯虚函数的类称为抽象类
    2. 抽象类不能实例化对象,但是可以定义指针和引用变量(指向派生类对象)

普通类定义指针,引用变量都可以,实例化对象也可以