我的基本理解是没有纯虚函数的实现,但是,我被告知可能有纯虚函数的实现。
class A {
public:
virtual void f() = 0;
};
void A::f() {
cout<<"Test"<<endl;
}
代码是否正常?
使用实现使其成为纯虚函数的目的是什么?
答案 0 :(得分:193)
纯virtual
函数必须在将直接实例化的派生类型中实现,但是基类型仍然可以定义实现。派生类可以通过使用完全范围的名称显式调用基类实现(如果访问权限允许)(在您的示例中调用A::f()
- 如果A::f()
是public
或{ {1}})。类似的东西:
protected
我能想到的用例是当有一个或多或少合理的默认行为时,但是类设计者希望只显式调用默认行为。也可能是您希望派生类始终执行自己的工作但也能够调用一组通用功能的情况。
请注意,尽管语言允许,但这并不是我常用的东西(事实上它可以完成似乎让大多数C ++程序员,甚至是经验丰富的程序员都感到惊讶)。
答案 1 :(得分:69)
要清楚,你误解了什么= 0;在虚函数意味着之后。
= 0表示派生类必须提供实现,而不是基类不能提供实现。
实际上,当你将虚函数标记为纯(= 0)时,提供定义几乎没有意义,因为除非有人通过Base :: Function(...)明确地这样做,否则永远不会调用它。或者如果Base类构造函数调用有问题的虚函数。
答案 2 :(得分:20)
它的优点是它强制派生类型仍然覆盖方法,但也提供默认或附加实现。
答案 3 :(得分:16)
如果您的代码应该由派生类执行,但您不希望它直接执行 - 并且您希望强制它被覆盖。
您的代码是正确的,尽管总而言之这不是经常使用的功能,并且通常只在尝试定义纯虚拟析构函数时才会出现 - 在这种情况下,必须提供实现。有趣的是,一旦你从该类派生,你就不需要覆盖析构函数。
因此,纯虚函数的一个明智用法是将纯虚析构函数指定为“非最终”关键字。
以下代码非常正确:
class Base {
public:
virtual ~Base() = 0;
};
Base::~Base() {}
class Derived : public Base {};
int main() {
// Base b; -- compile error
Derived d;
}
答案 4 :(得分:5)
你必须给一个纯虚拟析构函数的主体,例如:)
阅读:http://cplusplus.co.il/2009/08/22/pure-virtual-destructor/
答案 5 :(得分:4)
是的,这是正确的。在您的示例中,从A派生的类继承了接口f()和默认实现。但是你强制派生类来实现方法f()(即使它只是调用A提供的默认实现)。
Scott Meyers在 Effective C ++(第2版)项目#36中讨论了这一点。区分接口的继承和实现的继承。最新版本中的项目编号可能已更改。
答案 6 :(得分:4)
包含或不包含主体的纯虚函数仅仅意味着派生类型必须提供自己的实现。
如果派生类想要调用基类实现,则基类中的纯虚函数体很有用。
答案 7 :(得分:2)
虚拟空虚foo()= 0;&#39;语法并不意味着你不能在当前类中实现foo(),你可以。 这并不意味着您必须在派生类中实现它。 在你打我之前,让我们观察钻石问题: (隐含代码,请注意)。
class A
{
public:
virtual void foo()=0;
virtual void bar();
}
class B : public virtual A
{
public:
void foo() { bar(); }
}
class C : public virtual A
{
public:
void bar();
}
class D : public B, public C
{}
int main(int argc, const char* argv[])
{
A* obj = new D();
**obj->foo();**
return 0;
}
现在,obj-&gt; foo()调用将导致B :: foo(),然后是C :: bar()。
你看......纯虚方法不必在派生类中实现(foo()在C类中没有实现 - 编译器会编译) 在C ++中存在很多漏洞。
希望我能提供帮助: - )
答案 8 :(得分:0)
具有带有实现主体的纯虚拟方法的一个重要用例是,当您想要一个抽象类,但是您在该类中没有任何合适的方法可以使它成为抽象类时纯虚拟的。在这种情况下,您可以将类的析构函数设为纯虚函数,并为此放置所需的实现(甚至是一个空的主体)。例如:
class Foo
{
virtual ~Foo() = 0;
void bar1() {}
void bar2(int x) {}
// other methods
};
Foo::~Foo()
{
}
此技术使Foo
类抽象化,因此无法直接实例化该类。同时,您没有添加其他纯虚拟方法来使Foo
类抽象。