纯虚函数的概念:
纯虚函数(pure virtual function),是指没有具体实现的虚成员函数。它用于这样的情况:设计一个类型时,会遇到无法定义类型中虚函数的具体实现,其实现依赖于不同的派生类。
定义纯虚函数的一般格式为:
virtual返回类型函数名(参数表)= 0;
“=0"表明程序员将不定义该虚函数实现,没有函数体,只有函数的声明;
函数的声明是为了在虚函数表中保留一个位置。"=O"本质上是将指向函数体的指针定义为nullptr。
抽象类的概念:
含有纯虚函数的类是抽象类。
抽象类是一种特殊的类,它是为抽象的目而建立的,它处于继承层次结构的较上层。
抽象类不能实例化对象,因为纯虚函数没有实现部分,所以含有纯虚函数类型不能实例化对象;
抽象类的概念:
含有纯虚函数的类是抽象类。
抽象类是一种特殊的类,它是为抽象的目而建立的,它处于继承层次结构的较上层。
抽象类不能实例化对象,因为纯虚函数没有实现部分,所以含有纯虚函数类型不能实例化对象;抽象类的主要作用:
将相关的类型组织在一个继承层次结构中,抽象类为派生类型提供一个公共的根,相关的派生类型是从这个根派生而来。
// 实现一个图形库
// 有圆 Circle;
// 有正方形 Square;
// 有矩形 Rectangel;
// 行为或方法
// draw() 绘图
// area() 计算面积
//实现类 ; 是继承了接口或抽象类型,定义了纯虚函数的实现;
class Shape
{
private:
string _sname;
public:
Shape(const string& name) :_sname(name)
{
cout << "Create Shape" << endl;
}
~Shape()
{
cout << "Destroy Shape" << endl;
}
public:
virtual void draw() const = 0;
virtual float area() const = 0;
};
class Circle : public Shape
{
private:
static const float pi;
float _radius;
public:
Circle(float r = 0.0) :_radius(r) {}
~Circle() {}
void draw() const
{
cout << "Draw ==> Circle" << endl;
}
float area() const
{
return pi * _radius * _radius;
}
};
const float Circle::pi = 3.14f;
class Square : public Shape
{
private:
float _length;
public:
Square(float a = 0.0) :_length(a) {}
~Square() {}
void draw() const
{
cout << "Draw ==> Square: " << endl;
}
float area() const
{
return _length * _length;
}
};
// Shape::vftable;
RTTI::Shape
__purecall
__purecall
class Rectangel : public Shape
{
private:
float _long;
float _wide;
public:
};
int main()
{
Circle c1(10);
Square sq(20);
Shape* sp = nullptr;
sp = &c1;
sp->draw();
cout << sp->area() << endl;
return 0;
}
(1)抽象类只能用作其他类的基类,不能创建抽象类的对象。(2)抽象类不能用作参数类型、函数返回类型或显式类型转换。
(3)可以定义抽象类的指针和引用,此指针可以指向(引用可以引用)它的派生类的对象,从而实现运行时多态。
注意:
抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类没有重新定义纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体类型。
公有继承的概念看起来很简单,进一步分析,会发现它由两个可分的部分组成:函数接口的继承和函数实现的继承。
为类的设计者:
有时希望派生类只继承成员函数的接口(声明),纯虚函数;
有时希望派生类同时继承函数的接口和实现,但允许派生类改写实现,虚函数。
有时则希望同时继承接口和实现,并且不允许派生类改写任何东西,非虚函数。
final:
C++11中增加了 final关键字来限制某个类不能被继承,或者某个虚函数不能被重写。如果修饰函数,final只能修饰虚函数,并且要放到类或者函数的后面。下面是 final 的用法∶
class A
{
public:
// final //限定该虚函数不能被重写
virtual void fun() final;
// Error∶non-virtual function cannot be final,只能修饰虚函数
void bar() final;
};
class B final : public A // class B is final 不能派生出新的类型,不能被继承
{
public:
// Error:fun cannot be overridden as it's final in A
virtual void fun(); //
};
class C : public B //Error: B is final class
{
};
override
override 关键字确保在派生类中声明的重写函数与基类的虚函数有相同的签名,同时也明确表明将会重写基类的虚函数,还可以防止因疏忽把本来想重写基类的虚函数声明成隐藏。这样,既可以保证重写虚函数的正确性,又可以提高代码的可读性。override关键字和 final关键字一样,需要放到方法后面。
class A
{
public:
virtual void func() {}
};
class B : public A
{
public:
void func() override
{
}
};