C ++非多态接口

时间:2012-08-24 08:22:31

标签: c++ inheritance polymorphism virtual

简单地说,如何在C ++中为单一级别的继承创建接口(出于简单和说明的原因)?我看到一些代码没有使用多态,但是基类包含一个虚拟抽象方法(virtual void TheMethod() = 0)。

现在,一个类是使用纯虚方法从这个抽象类派生的,但在后续代码中,派生类的实例在没有动态分配的情况下使用。

这是正确的方法吗?使用多态设计推断出的开销是多少?

我认为这是不可能的..这看起来更像隐藏/重影基本方法,即使该方法是纯虚拟方法。

稍后编辑:感谢所有能够提供一些好答案的人,我想强调一下由于使用“动态分配”而产生的严重错误,其意思是强调这一点对象创建的可能性是唯一与多态性兼容的可能性。很明显,使用这种运行时调用行为并不是唯一的方法(但也许是最常见的?),但为了进一步澄清我原来的问题:

有没有办法强制程序员在不使用纯虚方法的情况下实现方法?我可能没有道理的关注是,打开多态设计的大门是否也有点沉重性能方面(每秒对讨论中的方法进行数千次这样的调用)。

甚至后来编辑:使基础有一个受保护的构造函数意味着它不能直接实例化(除了使用工厂或其他友好的手段),这可以解决补偿纯虚拟的影响之一方法诱导。但是如何确保任何派生类仍然提供自己的方法实现?如果对相关vtable的夸大担忧实际上并不是那么重要,那么我将坚持使用纯虚方法(因为SFINAE,奇怪的重复模板模式更难以阅读和理解最不熟练的C ++程序员 - 像我一样:))。

4 个答案:

答案 0 :(得分:5)

出于教学原因,如果目标是了解如何实施 C ++中的多态对象,并测试一个人创建的类型,动态 分配是没有必要的。然而,在实际应用中,它可能 因为使用多态的主要原因是因为 具体类型直到运行时才会知道。

请注意,在C ++中(以及几乎所有其他支持的语言) it),多态性需要引用语义,而不是值 默认情况下C ++使用的语义。通常,设计的类是 用作基类的支持复制和赋值(除了 可能通过虚拟clone()函数)。

关于开销:与什么相比?呼叫虚拟 函数通常比调用非虚函数更昂贵 功能。但是如果你正在使用虚拟功能,那是因为你需要 运行时调度;可能使用其他一些机制模拟这个 甚至更贵。

答案 1 :(得分:3)

您不必动态分配对象以多态方式使用它:

struct base {
    virtual void foo() = 0;
};

struct derived : base {
    virtual void foo() {
        // do stuff
    }
};

void f(base& object) {
    object.foo();
}

int main() {
    derived object; // no dynamic allocation at all
    f(object); // polymorphism happens here
}

答案 2 :(得分:2)

是的,正如其他人所说,你基本上使用具有纯虚拟(抽象)成员函数的类而没有数据成员。当实现此接口时,您自然必须提供这些方法。

另一方面,这与动态分配无关。您是否拥有自动对象(即堆栈)或动态对象(即堆)与您使用它们的方式无关,包括多态性。你的意思是动态绑定

现在,说了这么多,你可以实现一个接口而不使用动态绑定(即“多态”)和模板。基本上,您将使用SFINAE + CRTP通过私有继承模板类来检查给定的成员函数是否存在。基本上,您的父类(不包含虚拟成员)template <typename T> class FooIface;(继承自class Foo : private FooIface<Foo>)将通过尝试调用它来确保T具有成员函数foo。使用元编程技巧,您还可以确保foo具有正确的类型。

但这可能太麻烦而且难以阅读。抽象基类是常用的方法。

答案 3 :(得分:1)

C ++中没有 接口 的概念,
您只能使用 Abstract class 模拟行为。
抽象类是一个至少有一个纯虚函数的类,一个不能创建抽象类的任何实例,但你可以创建指针和引用它。此外,从抽象类继承的每个类都必须实现纯虚函数,以便可以创建它的实例。

动态分配 多态 无关!

动态分配 定义 对象将被分配,对象应具有明确的内存管理功能为自动变量提供的隐式内存管理。

多态性 表示 多种形式的一件事 。这是在类中具有不同行为的相同函数。您可以将Base类指针指向堆栈上的对象,并且仍然具有多态行为。