C++ 虚拟/纯虚拟解释
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1306778/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Virtual/pure virtual explained
提问by Justin
What exactly does it mean if a function is defined as virtual and is that the same as pure virtual?
如果一个函数被定义为虚函数并且与纯虚函数相同,这究竟是什么意思?
采纳答案by Diego Dias
From Wikipedia's Virtual function...
从维基百科的虚拟功能...
In object-oriented programming, in languages such as C++, and Object Pascal, a virtual function or virtual method is an inheritable and overridable function or method for which dynamic dispatch is facilitated. This concept is an important part of the (runtime) polymorphism portion of object-oriented programming (OOP). In short, a virtual function defines a target function to be executed, but the target might not be known at compile time.
在面向对象编程中,在诸如 C++ 和 Object Pascal 之类的语言中,虚函数或虚方法是可继承和可覆盖的函数或方法,便于动态调度。这个概念是面向对象编程 (OOP) 的(运行时)多态性部分的重要组成部分。简而言之,虚函数定义了要执行的目标函数,但在编译时可能不知道目标函数。
Unlike a non-virtual function, when a virtual function is overridden the most-derived version is used at all levels of the class hierarchy, rather than just the level at which it was created. Therefore if one method of the base class callsa virtual method, the version defined in the derived class will be used instead of the version defined in the base class.
与非虚函数不同,当一个虚函数被覆盖时,派生最多的版本将用于类层次结构的所有级别,而不仅仅是创建它的级别。因此,如果基类的一个方法调用虚方法,将使用派生类中定义的版本,而不是基类中定义的版本。
This is in contrast to non-virtual functions, which can still be overridden in a derived class, but the "new" version will only be used by the derived class and below, but will not change the functionality of the base class at all.
这与非虚函数形成对比,非虚函数仍然可以在派生类中被覆盖,但“新”版本只会被派生类及以下类使用,而根本不会改变基类的功能。
whereas..
然而..
A pure virtual function or pure virtual method is a virtual function that is required to be implemented by a derived class if the derived class is not abstract.
纯虚函数或纯虚方法是如果派生类不是抽象的,则需要由派生类实现的虚函数。
When a pure virtual method exists, the class is "abstract" and can not be instantiated on its own. Instead, a derived class that implements the pure-virtual method(s) must be used. A pure-virtual isn't defined in the base-class at all, so a derived class mustdefine it, or that derived class is also abstract, and can not be instantiated. Only a class that has no abstract methods can be instantiated.
当存在纯虚方法时,该类是“抽象的”,不能自行实例化。相反,必须使用实现纯虚拟方法的派生类。基类中根本没有定义纯虚拟,因此派生类必须定义它,否则派生类也是抽象的,无法实例化。只有没有抽象方法的类才能被实例化。
A virtual provides a way to override the functionality of the base class, and a pure-virtual requiresit.
虚拟提供了一种覆盖基类功能的方法,而纯虚拟需要它。
回答by Asik
I'd like to comment on Wikipedia's definition of virtual, as repeated by several here. [At the time this answer was written,] Wikipedia defined a virtual method as one that can be overridden in subclasses. [Fortunately, Wikipedia has been edited since, and it now explains this correctly.] That is incorrect: any method, not just virtual ones, can be overridden in subclasses. What virtual does is to give you polymorphism, that is, the ability to select at run-time the most-derived override of a method.
我想评论维基百科对虚拟的定义,正如这里有几个人重复的那样。[在撰写此答案时,] 维基百科将虚拟方法定义为可以在子类中覆盖的方法。[幸运的是,维基百科已经被编辑,现在它正确地解释了这一点。] 这是不正确的:任何方法,不仅仅是虚拟方法,都可以在子类中被覆盖。virtual 的作用是为您提供多态性,即能够在运行时选择最派生的方法覆盖。
Consider the following code:
考虑以下代码:
#include <iostream>
using namespace std;
class Base {
public:
void NonVirtual() {
cout << "Base NonVirtual called.\n";
}
virtual void Virtual() {
cout << "Base Virtual called.\n";
}
};
class Derived : public Base {
public:
void NonVirtual() {
cout << "Derived NonVirtual called.\n";
}
void Virtual() {
cout << "Derived Virtual called.\n";
}
};
int main() {
Base* bBase = new Base();
Base* bDerived = new Derived();
bBase->NonVirtual();
bBase->Virtual();
bDerived->NonVirtual();
bDerived->Virtual();
}
What is the output of this program?
这个程序的输出是什么?
Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.
Derived overrides every method of Base: not just the virtual one, but also the non-virtual.
Derived 覆盖了 Base 的每一个方法:不仅是虚拟的,还有非虚拟的。
We see that when you have a Base-pointer-to-Derived (bDerived), calling NonVirtual calls the Base class implementation. This is resolved at compile-time: the compiler sees that bDerived is a Base*, that NonVirtual is not virtual, so it does the resolution on class Base.
我们看到,当你有一个 Base-pointer-to-Derived (bDerived) 时,调用 NonVirtual 会调用 Base 类的实现。这是在编译时解决的:编译器看到 bDerived 是一个 Base*,NonVirtual 不是虚拟的,所以它在类 Base 上进行解析。
However, calling Virtual calls the Derived class implementation. Because of the keyword virtual, the selection of the method happens at run-time, not compile-time. What happens here at compile-time is that the compiler sees that this is a Base*, and that it's calling a virtual method, so it insert a call to the vtable instead of class Base. This vtable is instantiated at run-time, hence the run-time resolution to the most-derived override.
但是,调用 Virtual 会调用 Derived 类实现。由于关键字 virtual,方法的选择发生在运行时,而不是编译时。在编译时这里发生的事情是编译器看到这是一个 Base*,并且它正在调用一个虚方法,因此它插入对 vtable 的调用而不是类 Base。这个 vtable 在运行时被实例化,因此运行时解析为最派生的覆盖。
I hope this wasn't too confusing. In short, any method can be overridden, but only virtual methods give you polymorphism, that is, run-time selection of the most derived override. In practice, however, overriding a non-virtual method is considered bad practice and rarely used, so many people (including whoever wrote that Wikipedia article) think that only virtual methods can be overridden.
我希望这不会太令人困惑。简而言之,任何方法都可以被覆盖,但只有虚方法才能为您提供多态性,即运行时选择最派生的覆盖。然而,在实践中,覆盖非虚拟方法被认为是不好的做法并且很少使用,所以很多人(包括写维基百科文章的人)认为只有虚拟方法可以被覆盖。
回答by JBRWilkinson
The virtual keyword gives C++ its' ability to support polymorphism. When you have a pointer to an object of some class such as:
virtual 关键字使 C++ 能够支持多态。当您有指向某个类的对象的指针时,例如:
class Animal
{
public:
virtual int GetNumberOfLegs() = 0;
};
class Duck : public Animal
{
public:
int GetNumberOfLegs() { return 2; }
};
class Horse : public Animal
{
public:
int GetNumberOfLegs() { return 4; }
};
void SomeFunction(Animal * pAnimal)
{
cout << pAnimal->GetNumberOfLegs();
}
In this (silly) example, the GetNumberOfLegs() function returns the appropriate number based on the class of the object that it is called for.
在这个(愚蠢的)示例中,GetNumberOfLegs() 函数根据调用它的对象的类返回适当的数字。
Now, consider the function 'SomeFunction'. It doesn't care what type of animal object is passed to it, as long as it is derived from Animal. The compiler will automagically cast any Animal-derived class to a Animal as it is a base class.
现在,考虑函数“SomeFunction”。它不关心传递给它的是什么类型的动物对象,只要它是从 Animal 派生的。编译器会自动将任何 Animal 派生类转换为 Animal ,因为它是基类。
If we do this:
如果我们这样做:
Duck d;
SomeFunction(&d);
it'd output '2'. If we do this:
它会输出'2'。如果我们这样做:
Horse h;
SomeFunction(&h);
it'd output '4'. We can't do this:
它会输出'4'。我们不能这样做:
Animal a;
SomeFunction(&a);
because it won't compile due to the GetNumberOfLegs() virtual function being pure, which means it must be implemented by deriving classes (subclasses).
因为它不会编译,因为 GetNumberOfLegs() 虚函数是纯的,这意味着它必须通过派生类(子类)来实现。
Pure Virtual Functions are mostly used to define:
纯虚函数主要用于定义:
a) abstract classes
a) 抽象类
These are base classes where you have to derive from them and then implement the pure virtual functions.
这些是基类,您必须从中派生,然后实现纯虚函数。
b) interfaces
b) 接口
These are 'empty' classes where all functions are pure virtual and hence you have to derive and then implement all of the functions.
这些是“空”类,其中所有函数都是纯虚拟的,因此您必须派生并实现所有函数。
回答by Nick Haddad
In a C++ class, virtualis the keyword which designates that, a method can be overridden (i.e. implemented by) a subclass. For example:
在 C++ 类中,virtual是关键字,它指定一个方法可以被子类覆盖(即由子类实现)。例如:
class Shape
{
public:
Shape();
virtual ~Shape();
std::string getName() // not overridable
{
return m_name;
}
void setName( const std::string& name ) // not overridable
{
m_name = name;
}
protected:
virtual void initShape() // overridable
{
setName("Generic Shape");
}
private:
std::string m_name;
};
In this case a subclass can override the the initShapefunction to do some specialized work:
在这种情况下,子类可以覆盖initShape函数来做一些特殊的工作:
class Square : public Shape
{
public:
Square();
virtual ~Square();
protected:
virtual void initShape() // override the Shape::initShape function
{
setName("Square");
}
}
The term pure virtualrefers to virtual functions that need to be implemented by a subclass and have not been implemented by the base class. You designate a method as pure virtual by using the virtualkeyword and adding a =0at the end of the method declaration.
术语纯虚拟是指需要由子类实现而基类尚未实现的虚函数。您可以通过使用virtual关键字并在方法声明的末尾添加=0来将方法指定为纯虚拟方法。
So, if you wanted to make Shape::initShape pure virtual you would do the following:
因此,如果您想让 Shape::initShape 纯虚拟,您可以执行以下操作:
class Shape
{
...
virtual void initShape() = 0; // pure virtual method
...
};
By adding a pure virtual method to your class you make the class an abstract base classwhich is very handy for separating interfaces from implementation.
通过向类中添加纯虚拟方法,您可以使类成为抽象基类,这对于将接口与实现分离非常方便。
回答by John Millikin
"Virtual" means that the method may be overridden in subclasses, but has an directly-callable implementation in the base class. "Pure virtual" means it is a virtual method with no directly-callable implementation. Such a method mustbe overridden at least once in the inheritance hierarchy -- if a class has any unimplemented virtual methods, objects of that class cannot be constructed and compilation will fail.
“虚拟”意味着该方法可以在子类中被覆盖,但在基类中具有可直接调用的实现。“纯虚拟”意味着它是一个没有可直接调用的实现的虚拟方法。这样的方法必须在继承层次结构中至少被覆盖一次——如果一个类有任何未实现的虚方法,则该类的对象不能被构造并且编译将失败。
@quark points out that pure-virtual methods canhave an implementation, but as pure-virtual methods must be overridden, the default implementation can't be directly called. Here is an example of a pure-virtual method with a default:
@quark 指出纯虚拟方法可以有实现,但由于必须覆盖纯虚拟方法,因此不能直接调用默认实现。下面是一个带有默认值的纯虚拟方法的例子:
#include <cstdio>
class A {
public:
virtual void Hello() = 0;
};
void A::Hello() {
printf("A::Hello\n");
}
class B : public A {
public:
void Hello() {
printf("B::Hello\n");
A::Hello();
}
};
int main() {
/* Prints:
B::Hello
A::Hello
*/
B b;
b.Hello();
return 0;
}
According to comments, whether or not compilation will fail is compiler-specific. In GCC 4.3.3 at least, it won't compile:
根据评论,编译是否会失败取决于编译器。至少在 GCC 4.3.3 中,它不会编译:
class A {
public:
virtual void Hello() = 0;
};
int main()
{
A a;
return 0;
}
Output:
输出:
$ g++ -c virt.cpp
virt.cpp: In function ‘int main()':
virt.cpp:8: error: cannot declare variable ‘a' to be of abstract type ‘A'
virt.cpp:1: note: because the following virtual functions are pure within ‘A':
virt.cpp:3: note: virtual void A::Hello()
回答by McMurdo
How does the virtual keyword work?
virtual 关键字如何工作?
Assume that Man is a base class, Indian is derived from man.
假设 Man 是一个基类,Indian 是从 man 派生出来的。
Class Man
{
public:
virtual void do_work()
{}
}
Class Indian : public Man
{
public:
void do_work()
{}
}
Declaring do_work() as virtual simply means: which do_work() to call will be determined ONLY at run-time.
将 do_work() 声明为虚拟只是意味着:调用哪个 do_work() 将仅在运行时确定。
Suppose I do,
假设我这样做,
Man *man;
man = new Indian();
man->do_work(); // Indian's do work is only called.
If virtual is not used, the same is statically determined or statically bound by the compiler, depending on what object is calling. So if an object of Man calls do_work(), Man's do_work() is called EVEN THOUGH IT POINTS TO AN INDIAN OBJECT
如果未使用 virtual,则由编译器静态确定或静态绑定,具体取决于调用的对象。因此,如果 Man 的对象调用 do_work(),则即使它指向印度对象,也会调用 Man 的 do_work()
I believe that the top voted answer is misleading - Any method whether or not virtual can have an overridden implementation in the derived class. With specific reference to C++ the correct difference is run-time (when virtual is used) binding and compile-time (when virtual is not used but a method is overridden and a base pointer is pointed at a derived object) binding of associated functions.
我认为投票最高的答案具有误导性 - 任何方法是否虚拟都可以在派生类中具有覆盖实现。对于 C++ 的特定参考,正确的区别是相关函数的运行时(当使用虚拟时)绑定和编译时(当不使用虚拟但方法被覆盖并且基指针指向派生对象时)绑定。
There seems to be another misleading comment that says,
似乎还有另一个误导性评论说,
"Justin, 'pure virtual' is just a term (not a keyword, see my answer below) used to mean "this function cannot be implemented by the base class."
“贾斯汀,‘纯虚拟’只是一个术语(不是关键字,见下面我的回答),用来表示“这个函数不能由基类实现”。
THIS IS WRONG! Purely virtual functions can also have a body AND CAN BE IMPLEMENTED! The truth is that an abstract class' pure virtual function can be called statically! Two very good authors are Bjarne Stroustrup and Stan Lippman.... because they wrote the language.
这是错误的!纯虚函数也可以有实体并且可以实现!事实是抽象类的纯虚函数可以静态调用!两位非常出色的作者是 Bjarne Stroustrup 和 Stan Lippman……因为他们编写了语言。
回答by rashedcs
A virtual function is a member function that is declared in a base class and that is redefined by derived class.Virtual function are hierarchical in order of inheritance. When a derived class does not override a virtual function, the function defined within its base class is used.
虚函数是在基类中声明并由派生类重新定义的成员函数。虚函数按继承顺序分层。当派生类不覆盖虚函数时,将使用其基类中定义的函数。
A pure virtual function is one that contains no definition relative to the base class.It has no implementation in the base class. Any derived class must override this function.
纯虚函数是不包含与基类相关的定义的函数。它在基类中没有实现。任何派生类都必须覆盖此函数。
回答by PJT
Simula, C++, and C#, which use static method binding by default, the programmer can specify that particular methods should use dynamic binding by labeling them as virtual. Dynamic method binding is central to object-oriented programming.
Simula、C++ 和 C# 默认使用静态方法绑定,程序员可以通过将它们标记为虚拟来指定特定方法应该使用动态绑定。动态方法绑定是面向对象编程的核心。
Object oriented programming requires three fundamental concepts: encapsulation, inheritance, and dynamic method binding.
面向对象编程需要三个基本概念:封装、继承和动态方法绑定。
Encapsulationallows the implementation details of an abstraction to be hidden behind a simple interface.
Inheritanceallows a new abstraction to be defined as an extension or refinement of some existing abstraction, obtaining some or all of its characteristics automatically.
Dynamic method bindingallows the new abstraction to display its new behavior even when used in a context that expects the old abstraction.
封装允许抽象的实现细节隐藏在一个简单的接口后面。
继承允许将新的抽象定义为某些现有抽象的扩展或细化,自动获得其部分或全部特征。
即使在需要旧抽象的上下文中使用时,动态方法绑定也允许新抽象显示其新行为。
回答by johannes_lalala
Virtual methods CAN be overridden by deriving classes, but need an implementation in the base class (the one that will be overridden)
虚拟方法可以被派生类覆盖,但需要在基类中实现(将被覆盖的那个)
Pure virtual methods have no implementation the base class. They need to be defined by derived classes. (So technically overridden is not the right term, because there's nothing to override).
纯虚方法没有实现基类。它们需要由派生类定义。(所以从技术上讲,覆盖不是正确的术语,因为没有什么可以覆盖的)。
Virtual corresponds to the default java behaviour, when the derived class overrides a method of the base class.
当派生类覆盖基类的方法时,虚拟对应于默认的 java 行为。
Pure Virtual methods correspond to the behaviour of abstract methods within abstract classes. And a class that only contains pure virtual methods and constants would be the cpp-pendant to an Interface.
纯虚方法对应于抽象类中抽象方法的行为。一个只包含纯虚方法和常量的类将是接口的 cpp 挂件。
回答by Sohail xIN3N
Virtual functions must have a definition in base class and also in derived class but not necessary, for example ToString() or toString() function is a Virtual so you can provide your own implementation by overriding it in user-defined class(es).
Virtual functions are declared and defined in normal class.
Pure virtual function must be declared ending with "= 0" and it can only be declared in abstract class.
An abstract class having a pure virtual function(s) cannot have a definition(s) of that pure virtual functions, so it implies that implementation must be provided in class(es) that derived from that abstract class.
虚函数必须在基类和派生类中都有定义,但不是必需的,例如 ToString() 或 toString() 函数是 Virtual ,因此您可以通过在用户定义的类中覆盖它来提供自己的实现。
虚函数在普通类中声明和定义。
纯虚函数必须以“= 0”结尾,并且只能在抽象类中声明。
具有纯虚函数的抽象类不能具有该纯虚函数的定义,因此这意味着必须在从该抽象类派生的类中提供实现。