如何设置表示接口的类?这只是一个抽象基类吗?
当前回答
使用纯虚拟方法创建类。通过创建另一个重写这些虚拟方法的类来使用该接口。
纯虚拟方法是定义为虚拟并分配给0的类方法。
class IDemo
{
public:
virtual ~IDemo() {}
virtual void OverrideMe() = 0;
};
class Child : public IDemo
{
public:
virtual void OverrideMe()
{
// do stuff
}
};
其他回答
就我所能测试的而言,添加虚拟析构函数非常重要。我使用的是用new创建的对象,用delete销毁的对象。
如果不在接口中添加虚拟析构函数,则不会调用继承类的析构函数。
class IBase {
public:
virtual ~IBase() {}; // destructor, use it to call destructor of the inherit classes
virtual void Describe() = 0; // pure virtual method
};
class Tester : public IBase {
public:
Tester(std::string name);
virtual ~Tester();
virtual void Describe();
private:
std::string privatename;
};
Tester::Tester(std::string name) {
std::cout << "Tester constructor" << std::endl;
this->privatename = name;
}
Tester::~Tester() {
std::cout << "Tester destructor" << std::endl;
}
void Tester::Describe() {
std::cout << "I'm Tester [" << this->privatename << "]" << std::endl;
}
void descriptor(IBase * obj) {
obj->Describe();
}
int main(int argc, char** argv) {
std::cout << std::endl << "Tester Testing..." << std::endl;
Tester * obj1 = new Tester("Declared with Tester");
descriptor(obj1);
delete obj1;
std::cout << std::endl << "IBase Testing..." << std::endl;
IBase * obj2 = new Tester("Declared with IBase");
descriptor(obj2);
delete obj2;
// this is a bad usage of the object since it is created with "new" but there are no "delete"
std::cout << std::endl << "Tester not defined..." << std::endl;
descriptor(new Tester("Not defined"));
return 0;
}
如果在没有virtual~IBase(){};的情况下运行前面的代码;,您将看到从未调用析构函数Tester::~Tester()。
使用纯虚拟方法创建类。通过创建另一个重写这些虚拟方法的类来使用该接口。
纯虚拟方法是定义为虚拟并分配给0的类方法。
class IDemo
{
public:
virtual ~IDemo() {}
virtual void OverrideMe() = 0;
};
class Child : public IDemo
{
public:
virtual void OverrideMe()
{
// do stuff
}
};
在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的《基于价值语义和概念的多态性》(强烈推荐,此处解释了该技术的更好版本)中,研究了以下案例:
假设我有一个应用程序,在其中我使用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的继承权是恶语的基础。Sean Parent的价值语义和基于概念的多态性谈话。Pyry Jahkola的无继承多态性演讲和poly库文档。Zach Laine的实用类型擦除:用优雅的设计模式解决OOP问题。Andrzej的C++博客-类型Erasure第i、ii、iii和iv部分。ConceptC中混合对象和概念的运行时多态泛型编程++Boost.TypeErasure文档Adobe Poly文档Boost.Any,std::任何提案(修订版3),Boost.Spirit::hold_Any。
如果您只需要接口的静态绑定(没有虚拟的,没有接口类型本身的实例,接口仅作为指南):
#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();
}
您还可以考虑使用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.
};
推荐文章
- 为什么我的程序不能在Windows 7下用法语编译?
- 如何获取变量的类型?
- 什么是奇怪的重复模板模式(CRTP)?
- 连接两个向量的最佳方法是什么?
- 在c++中,是通过值传递更好,还是通过引用到const传递更好?
- 在STL中deque到底是什么?
- Windows上最好的免费c++分析器是什么?
- 如何自动转换强类型枚举为int?
- 在一个类中使用具有成员函数的泛型std::function对象
- 'for'循环中的后增量和前增量产生相同的输出
- 虚函数和纯虚函数的区别
- 转换List<DerivedClass>到List<BaseClass>
- c++中的_tmain()和main()有什么区别?
- 内存泄漏是否正常?
- 当启用c++ 11时,std::vector性能回归