如何设置表示接口的类?这只是一个抽象基类吗?
当前回答
使用纯虚拟方法创建类。通过创建另一个重写这些虚拟方法的类来使用该接口。
纯虚拟方法是定义为虚拟并分配给0的类方法。
class IDemo
{
public:
virtual ~IDemo() {}
virtual void OverrideMe() = 0;
};
class Child : public IDemo
{
public:
virtual void OverrideMe()
{
// do stuff
}
};
其他回答
虽然虚拟是定义接口的事实标准,但我们不要忘记经典的类C模式,它在C++中带有构造函数:
struct IButton
{
void (*click)(); // might be std::function(void()) if you prefer
IButton( void (*click_)() )
: click(click_)
{
}
};
// call as:
// (button.*click)();
这样做的优点是,您可以在运行时重新绑定事件,而无需再次构造类(因为C++没有用于更改多态类型的语法,这是变色龙类的一种变通方法)。
提示:
您可以将其作为基类继承(允许虚拟和非虚拟),并在后代的构造函数中填充单击。您可以将函数指针作为受保护的成员,并具有公共引用和/或getter。如上所述,这允许您在运行时切换实现。因此,这也是一种管理状态的方法。根据代码中ifs与状态变化的数量,这可能比switch()es或ifs更快(预计周转时间在3-4个ifs左右,但始终要先测量。如果在函数指针上选择std::function<>,则可能能够管理IBase中的所有对象数据。从这一点开始,您可以获得IBase的值示意图(例如,std::vector<IBase>将起作用)。注意,根据编译器和STL代码的不同,这可能会更慢;此外,与函数指针甚至虚拟函数相比,std::function<>的当前实现往往会有开销(这在将来可能会改变)。
您还可以考虑使用NVI(非虚拟接口模式)实现的合约类。例如:
struct Contract1 : boost::noncopyable
{
virtual ~Contract1() = default;
void f(Parameters p) {
assert(checkFPreconditions(p)&&"Contract1::f, pre-condition failure");
// + class invariants.
do_f(p);
// Check post-conditions + class invariants.
}
private:
virtual void do_f(Parameters p) = 0;
};
...
class Concrete : public Contract1, public Contract2
{
private:
void do_f(Parameters p) override; // From contract 1.
void do_g(Parameters p) override; // From contract 2.
};
使用纯虚拟方法创建类。通过创建另一个重写这些虚拟方法的类来使用该接口。
纯虚拟方法是定义为虚拟并分配给0的类方法。
class IDemo
{
public:
virtual ~IDemo() {}
virtual void OverrideMe() = 0;
};
class Child : public IDemo
{
public:
virtual void OverrideMe()
{
// do stuff
}
};
class Shape
{
public:
// pure virtual function providing interface framework.
virtual int getArea() = 0;
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
class Rectangle: public Shape
{
public:
int getArea()
{
return (width * height);
}
};
class Triangle: public Shape
{
public:
int getArea()
{
return (width * height)/2;
}
};
int main(void)
{
Rectangle Rect;
Triangle Tri;
Rect.setWidth(5);
Rect.setHeight(7);
cout << "Rectangle area: " << Rect.getArea() << endl;
Tri.setWidth(5);
Tri.setHeight(7);
cout << "Triangle area: " << Tri.getArea() << endl;
return 0;
}
结果:矩形面积:35三角形面积:17
我们已经看到了抽象类是如何根据getArea()定义接口的,另外两个类实现了相同的函数,但使用了不同的算法来计算特定于形状的面积。
如果您只需要接口的静态绑定(没有虚拟的,没有接口类型本身的实例,接口仅作为指南):
#include <iostream>
#include <string>
// Static binding interface
// Notice: instantiation of this interface should be usefuless and forbidden.
class IBase {
protected:
IBase() = default;
~IBase() = default;
public:
// Methods that must be implemented by the derived class
void behaviorA();
void behaviorB();
void behaviorC() {
std::cout << "This is an interface default implementation of bC().\n";
};
};
class CCom : public IBase {
std::string name_;
public:
void behaviorA() { std::cout << "CCom bA called.\n"; };
};
class CDept : public IBase {
int ele_;
public:
void behaviorB() { std::cout << "CDept bB called.\n"; };
void behaviorC() {
// Overwrite the interface default implementation
std::cout << "CDept bC called.\n";
IBase::behaviorC();
};
};
int main(void) {
// Forbid the instantiation of the interface type itself.
// GCC error: ‘constexpr IBase::IBase()’ is protected within this context
// IBase o;
CCom acom;
// If you want to use these interface methods, you need to implement them in
// your derived class. This is controled by the interface definition.
acom.behaviorA();
// ld: undefined reference to `IBase::behaviorB()'
// acom.behaviorB();
acom.behaviorC();
CDept adept;
// adept.behaviorA();
adept.behaviorB();
adept.behaviorC();
// adept.IBase::behaviorC();
}
推荐文章
- 什么是“参数依赖查找”(又名ADL,或“Koenig查找”)?
- 公共朋友交换成员函数
- 如何在Go中使用c++
- 自定义c++分配器的引人注目的例子?
- RAII和c++中的智能指针
- 如何构建和使用谷歌TensorFlow c++ api
- 接口方法的最终参数-有什么意义?
- 断言是邪恶的吗?
- 下面这些短语在c++中是什么意思:0 -,default-和value-initialization?
- 在STL地图中,使用map::insert比[]更好吗?
- C++ Linux的想法?
- 如何为Fedora安装g++ ?
- Std::cin输入空格?
- c++标准是否要求iostreams的性能很差,或者我只是在处理一个糟糕的实现?
- 我怎么知道什么时候创建一个接口?