开发者

What is the most concise yet accurate way to describe what a virtual function is in C++?

Being asked to describe what a virtual function is seems to be one of the most common questions in interviews assessing basic C++ knowledge. However, after several years programming C++, I still have the uncomfortable feeling that I don't really understand how best to define what they are.

If I consult wikipedia, I see the definition of virtual function is:

"In object-oriented programming, a virtual function or virtual method is a function or method whose behaviour can be overridden within an inheriting class by a function with the same signature"

This definition seems simple and elegant, and not C++ specific. But to me it doesn't seem to capture t开发者_如何学Che concept of a virtual function in C++, since surely a non-virtual function can also be overridden within an inheriting class by a function with the same signature.

If I'm asked to describe what a virtual function is informally, I say something about pointers like "it's a method such that when you call it via a base class pointer, the version of it defined in the derived class is called instead, if the pointer actually points to an instance of a derived class". This doesn't seem like a very elegant description of the concept. I know that people say this is how "polymorphism" is achieved in C++ (polymorphism, as far as I understand, roughly being the whole idea of organizing objects into hierarchies), but I don't know of a fancier way to understand or explain the mechanism than to go through the example with the pointers.

I guess I'm confused about whether the "pointer" description of virtual functions is something fundamental to their definition, or just something incidental to their implementation in C++.


I've always thought that this quote captures the essence of virtual functions:

A virtual function is a way of defining a family of related behaviors that can be customized by the entities that actual have to do those behaviors.

If you ignore all the C++-isms of virtual functions - how having virtual functions enables dynamic_cast to work for objects of the class type, how they're only treated virtually if accessed through a pointer, how virtual destructors are completely different from virtual non-destructors, etc. - I think that the above statement gets at the heart of what virtual functions are all about.

The main reason I like this statement is that it describes virtual functions in a way that decouples them from programming. You could explain virtual functions to a non-technical person using this definition by giving some concrete analogies. For example, the idea of "turning on a light" could be thought of as a virtual function because the actual mechanics of what happens when you turn on a light depends entirely on the particular light you're using (incandescent? fluorescent? LED?), but the conceptual idea is the same in each case. Of course, it's not a perfect analogy, but I think it gets the point across well enough.

More generally, IMHO, if you're ever asked to describe something informally, try as much as possible to distance yourself from the particular programming language you're using and, if at all possible, from computers at all. Try to think of the most general setting in which the concept applies, and then describe it at that level. Then again, I teach introductory CS courses, and so I have a bit of a bias toward this domain, so I have no idea how applicable this is in a job interview setting. :-)


since surely a non-virtual function can also be overridden within an inheriting class by a function with the same signature.

No thats incorrect. The function only gets redefined not overriddden in that case.


Your informal definition is a good summary of what a virtual pointer does. It sounds like you're looking to also describe how it works, but since the C++ standard doesn't specify, any "how" description would be specific to a particular implementation and not the C++ language in general.

The C++ standard is all about behavior and says almost nothing about implementation. There's even the "as-if" rule, which allows any alternate implementation that provides the same visible behavior.


"I guess I'm confused about whether the "pointer" description of virtual functions is something fundamental to their definition, or just something incidental to their implementation in C++."

It is not incidental. The concept of virtual functions works only for pointers or references.


Virtual functions are needed when the derived class method bearing the same signature that of base class is overridden to different functionality.

class Polygon
{
    public:
    virtual float area()
    {
        std::cout << "\n No formula in general \n" ;
    }
    virtual ~Polygon();
};

class Square
{
    public:
    float area()
    {
        std::cout << "\n Side*Side \n" ; 
    }
    ~Square();
}

Polygon* obj = new Square ;
obj -> area() ;  // Ok, Square::area() is called. 

Square obj1;
Polygon& temp = obj1 ; // Ok, Square::area() is called

Square obj2;
Polygon temp1 = obj2 ; // Polygon::area() is called because of object slicing.


The difference lies in how the compiler decides which implementation to "bind" to the method call when it compiles the source code. For a virtual fumction, the implementation chosen is based on the actual concrete type of the object itself, not on the type of the variable. This means that when you cast an object to a base class or interface, the implementaion which will get executed is still the implementation defined on the derived class that the object actually is.

In puesdo code

// for a virtual function
public class Animal { public virtual void Move() { Print "An animal Moved." } }
public class Dog: Animal  { public void Move() { Print "A Dog Moved." } }

Animal x = new Dog();
x.Move()  // this will print "A Dog Moved."

For a non-virtual function, the implementation chosen will be based on the type of the variable, which means that when you cast an object to a base class, (i.e., change the type of the variable ) the method implementation defined in the base class will be chosen by the compiler and it will get executed, not the implementation in the derived class...

// for a non-virtual function
public class Animal { public void Move() { Print "An animal Moved." } }
public class Dog: Animal  { public void Move() { Print "A Dog Moved." } }

Animal x = new Dog();
x.Move() // this will print "An animal Moved."


Let's say that Beta is a subclass of Alpha, and it can either create a new method area() or it can add a virtual one.

There isn't a difference if you are talking to a Beta pointer. But if you are talking to a Alpha* which points at a Beta object, you will get Alpha's method. Unless you declare the function as virtual.

The Beta subclass has its function dispatch table, which is a copy of Alpha's table but with extra Beta methods at the end. If Beta merely overrides a method, it will go in Beta's section of the dispatch table, so references to Alpha* will not see the new method. But, if the new method is virtual, it will go in the Alpha section of Beta's class table.

More to the point, let's say you have a Circle subclass of Shape. And let's say you have a pointer to a Shape object, x, which happens to be an instance of Circle. x->area() will only see the portion of the function table that relates to Shape. If Circle does a virtual area function, it will appear in the Shape section of the table. If Circle merely overrides area, then the area method will be placed in the Circle portion of the table and the Shape * x will not see the new function.

In C++ there is only one function table per class. This is a bit confusing for people who are used to scripting language where each object has it's own dispatch table. Scripting languages are extremely inefficient in that way. Imagine all the space taken up for each object.


If an interview is about your knowledge in C++ I think there is not a sin to refer to a pointer.

You can say simply that "virtual functions is a mechanism to allow an object to express it's class behavior, even if it's accessed through a base class pointer".

More than this (if you think about "pure virtual functions") it's also a mechanism to force a whole hierarchy of classes to provide a specific method, without defining a default method implementation in the base class.


A virtual function is one where the callee decides the behaviour. A non-virtual function is one where the caller decides the behaviour.

Is that concise enough?


Although pointers are necessary for using virtual functions in C++, I would argue that pointers are incidental to the idea, and explanations that don't depend on pointers are clearer. I think that templatetypedef and Charles_Bretana hit the main idea.

The reason that pointers seem to creep in to descriptions of virtual functions is that only pointers and references can have different run-time vs. compile-time types. A variable whose type is class Foo must contain a Foo at run-time, so it doesn't matter whether a virtual function is used. But a variable whose type is class Foo * can point to any subclass of Foo, so this is the situation where virtual functions and non-virtual functions behave differently.


The Idea

The basic difference between virtual and non virtual method is when you bind the name of the method to the actual method implementation. A virtual method is bound at runtime based on the type. A non virtual function is bound at compile time.

Slightly more formerly:

A virtual method is one that can be overridden in a derived type.
Such that when the virtual method is called (via pointer or reference) runtime binding is applied to select the version of the method that is defined in the most derived version; based on the type of the actual object (being pointed at or referenced).

C++ notes

Note: A method is virtual even if you do not use the virtual keyword if an ancestor declares a method with the same signature as virtual.


Compiler aided mechanism of achieving dynamic polymorphism. Remember that C++ also supports static polymorphism via generic programming. And function pointers have always been there as the most primitive means of implementing dynamic polymorphism.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜