【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
如何设置代表接口的类? 这只是一个抽象的基类吗?
#1楼
如果您使用的是Microsoft的C ++编译器,那么您可以执行以下操作:
struct __declspec(novtable) IFoo
{
virtual void Bar() = 0;
};
class Child : public IFoo
{
public:
virtual void Bar() override { /* Do Something */ }
}
我喜欢这种方法,因为它会导致更小的接口代码,并且生成的代码大小可以显着缩小。 使用novtable删除对该类中vtable指针的所有引用,因此您永远不能直接实例化它。 请参阅此处的文档 - novtable 。
#2楼
在C ++ 11中,您可以轻松地完全避免继承:
struct Interface {
explicit Interface(SomeType& other)
: foo([=](){ return other.my_foo(); }),
bar([=](){ return other.my_bar(); }), /*...*/ {}
explicit Interface(SomeOtherType& other)
: foo([=](){ return other.some_foo(); }),
bar([=](){ return other.some_bar(); }), /*...*/ {}
// you can add more types here...
// or use a generic constructor:
template<class T>
explicit Interface(T& other)
: foo([=](){ return other.foo(); }),
bar([=](){ return other.bar(); }), /*...*/ {}
const std::function<void(std::string)> foo;
const std::function<void(std::string)> bar;
// ...
};
在这种情况下,接口具有引用语义,即您必须确保对象比接口更长(也可以使接口具有值语义)。
这些类型的接口有它们的优点和缺点:
- 它们需要比基于继承的多态性更多的内存 。
- 它们通常比基于继承的多态更快 。
- 在您了解最终类型的情况下, 它们会更快! (像gcc和clang这样的编译器在没有/继承具有虚函数的类型的类型中执行更多优化)。
最后,继承是复杂软件设计中所有邪恶的根源。 在Sean Parent的Value Semantics和基于概念的多态性中 (强烈推荐,此技术的更好版本在那里解释),研究了以下案例:
假设我有一个应用程序,我使用MyShape
接口以多态方式处理我的形状:
struct MyShape { virtual void my_draw() = 0; };
struct Circle : MyShape { void my_draw() { /* ... */ } };
// more shapes: e.g. triangle
在您的应用程序中,使用YourShape
界面对不同形状执行相同操作:
struct YourShape { virtual void your_draw() = 0; };
struct Square : YourShape { void your_draw() { /* ... */ } };
/// some more shapes here...
现在说你想使用我在你的应用程序中开发的一些形状。 从概念上讲,我们的形状具有相同的界面,但为了使我的形状在您的应用程序中工作,您需要扩展我的形状如下:
struct Circle : MyShape, YourShape {
void my_draw() { /*stays the same*/ };
void your_draw() { my_draw(); }
};
首先,根本不可能修改我的形状。 此外,多重继承引领了意大利面条代码的道路(想象一下,第三个项目就是使用了TheirShape
界面......如果他们也调用了他们的绘图函数my_draw
会发生什么?)。
更新:有一些关于基于非继承的多态性的新引用:
- 肖恩父母的继承是邪恶言论的基础 。
- Sean Parent的价值语义和基于概念的多态性谈话。
- Pyry Jahkola的继承自由多态论和poly库docs 。
- Zach Laine的实用型擦除:用优雅的设计模式解决OOP问题 。
- Andrzej的C ++博客 - Type Erasure部分i , ii , iii和iv 。
- 运行时多态泛型编程 - 混合ConceptC ++中的对象和概念
- Boost.TypeErasure docs
- Adobe Poly文档
- Boost.Any , std ::任何提案(修订版3) , Boost.Spirit :: hold_any 。
#3楼
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()定义接口,另外两个类实现相同的函数,但使用不同的算法来计算特定于形状的区域。
#4楼
用纯虚方法创建一个类。 通过创建覆盖这些虚拟方法的另一个类来使用该接口。
纯虚方法是一种定义为虚拟并分配给0的类方法。
class IDemo
{
public:
virtual ~IDemo() {}
virtual void OverrideMe() = 0;
};
class Child : public IDemo
{
public:
virtual void OverrideMe()
{
//do stuff
}
};
#5楼
除了C#/ Java中的抽象基类之外,你有一个特殊的接口类型类的全部原因是因为C#/ Java不支持多重继承。
C ++支持多重继承,因此不需要特殊类型。 没有非抽象(纯虚拟)方法的抽象基类在功能上等同于C#/ Java接口。
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3145107