接口类简介:
接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法。
-
因为接口只负责描述类的行为和功能,不需要实现,而是由它的派生类来实现。
-
至于普通抽象类,只要有一个成员函数被声明为纯虚函数,那它就是抽象类,这是和接口不一样的地方。
用c++实现接口类时需要注意一下几点:
1、接口类中不应该声明成员变量,静态变量。
2、可以声明静态常量作为接口的返回值状态,这些静态变量需要初始化,访问时需要使用"接口类型::静态常量名"访问
2、定义的接口方法使用virtual 修饰符 和 “=0” 修饰,表示该方法是纯虚的函数,实现该接口的子类必须实现这些方法后才能实例化。
3、因为接口类是虽然无法创建对象的,但应该编写虚析构函数,具体原因参考:C++中的虚析构函数
IShape.h
#ifndef ISHAPE_H
#define ISHAPE_H
#include <iostream>
class IShape
{
public:
virtual ~IShape()
{
std::cout << "~IShape() " << std::endl; //这里为了演示,实际中这里写成空函数体就可以了。
}
virtual int area() = 0;
static const int MIN_AREA = 10;
};
#endif // ISHAPE_H
IAction.h
#ifndef IACTION_H
#define IACTION_H
#include <iostream>
class IAction
{
public:
virtual ~IAction()
{
std::cout << " ~IAction()" << std::endl; //这里为了演示,实际中这里写成空函数体就可以了。
}
virtual void run() = 0;
};
#endif // IACTION_H
这样我们就定义了两个接口,我们来编写一个使用该接口的鸟类:
Bird.h
#ifndef BIRD_H
#define BIRD_H
#include "IAction.h"
#include "IShape.h"
class Bird : public IShape, public IAction
{
public:
Bird();
~Bird();
// IAction interface
public:
void run() override;
// IShape interface
int area() override;
};
#endif // BIRD_H
Bird.cpp
#include "bird.h"
#include <iostream>
Bird::Bird()
{
std::cout << "小鸟出生了" << std::endl;
}
Bird::~Bird()
{
std::cout << "小鸟离开了" << std::endl;
}
void Bird::run()
{
std::cout << "小鸟飞呀飞呀" << std::endl;
}
int Bird::area()
{
std::cout << "小鸟的形状像小鸡仔的形状" << std::endl;
std::cout << "Bird::area():" << IShape::MIN_AREA << std::endl; //这里访问常量是注意
return IShape::MIN_AREA;
}
#include "bird.h"
#include <iostream>
void doRun(IAction *object)
{
object->run();
}
void getArea(IShape *object)
{
object->area();
}
int main()
{
Bird *bird = new Bird();
doRun(bird);
getArea(bird);
delete bird;
getchar();
return 0;
}
运行结果
小鸟出生了
小鸟飞呀飞呀
小鸟的形状像小鸡仔的形状
Bird::area():10
小鸟离开了
~IAction()
~IShape()
其中的析构顺序和这个有关:
class Bird : public IShape, public IAction
从右往左看,先是public IAction,所以它的析构函数最新调用;然后是IShape,最后是Bird的析构函数。
如果换成:
class Bird : public IAction, public IShape,
那么析构函数被调用的顺序依次为~IShape() ~IAction(),最后是子类Bird的析构函数。
至于接口的析构函数是写成普通的虚函数,还是纯虚函数,本人理解是普通虚函数就可以了。(也可以写成纯虚函数,并写成空函数体,这种方式有点奇怪。可以看这个实例:C++接口定义及实现举例)
代码例子参考:
https://www.cnblogs.com/h2zZhou/p/10481501.html
原文没有虚析构函数,这是有严重问题的。具体原因可以看这个例子:
C++中的虚析构函数