Talk about virtual functions

Source: Internet
Author: User

Virtual, write C + + will not be unfamiliar, for the class of member functions, to express the nature of the object polymorphism.

declaring virtual functions for polymorphic base classes

Before reading, get a "golden law" ( This is wrong ):

You should always declare the destructor of a class with virtual

If you do not, then when the class becomes the base class, when the object memory is reclaimed, an incorrect behavior occurs, causing a memory leak. This is not the details.

At first glance, it makes sense, right?

But youth, not so young, easy to declare that virtual is to pay the price .

In C + +, the runtime judgment behavior of virtual is implemented based on the virtual function table of the class. virtual function tables are memory-intensive and can also produce efficiency problems.
So, using virtual correctly is [1]:

The base class of polymorphic (with polymorphic properties) should declare a virtual destructor. If class has any virtual functions, it should have a virtual destructor
The purpose of Classes is not to declare a virtual destructor if it is not used as a base classed, or is not intended for polymorphism.

When appropriate, declaring the virtual destructor to be correct.
Now consider the declaration of the abstract class.
An abstract class definition contains at least one pure-virtual function (a pure virtual function) in a class. Abstract class as a base class, there should also be a virtual destructor.
So, in the implementation, we can trickery, simply declare a pure-virtual destructor OK:

class SomeClass{public:    virtual ~SomeClass0// 然而还是要提供定义

This is a technique mentioned in [1].

Do not call the virtual function during construction and destruction

Suppose we want to do something at the same time that the class is constructed, similar to log, or update anything related to the instantiated object.
Well, let the class in the construction of the time to print their own class name good.
Wait, what if the class is inherited, and I want to detach the operation from the constructor.
OK, think carefully, so let the function become virtual good. Then there is the following implementation:

class Base{public:    Base//注意这里调用了virtual 函数    virtual ~Base(){}    virtualvoid0;};void Base::print(){ cout<<" Base "public Base{public:    Derived(){}    void print() { cout<<" Derived "<<endl; }};

* This implementation is not correct

So, what happens when we instantiate the derived class?

Derived d;

We thought it would output

Derived

But the real act is

Base

Why does the virtual function behave as if it were not a virtual function at this time?
Because the virtual function is not a virtual function during the base class construction. [1]

The answer is straightforward, so, for the above behavior, the version that print calls is the version of Base, because thetype of Derived class is actually base class when you execute that sentence. [1]

In fact, at compile time, there will be warning information:

Warning:pure virtual void Base::p rint () ' called from constructor
Base () {print ();}//Note here the virtual function is called

The explanation is also easy to understand: the constructor of base is earlier than the derived constructor, and when the constructor of base executes, the member variable of derived is in the uninitialized phase. If the virtual function falls to the derived class class, then the member variables obtained are derived class (but they are not initialized), which leads to ambiguous behavior of the program.

Corresponding to the destructor, the truth is the same, it is no longer explained here.

pure-virtual, Impure-virtual, non-virtual functions and the meanings of inheritance

When a class inherits, the member variables, member functions of the base class are inherited.

For the member function inheritance, but also can have pure-virtual, impure-virtual, non-virtual difference. (In this article, if you refer to the virtual function, that is impure-virtual)
For these inheritance, the meanings are differentiated as follows [1]:

    • Pure-virtual: Inherit interface only
    • Impure-virtual: Inheritance interface and default implementation
    • Non-virtual: Inheritance interfaces and mandatory implementation inheritance

* This section is based on [1] clause 35.

When the virtual function has default parameters

There are the following definitions:

class Base{public:    virtual ~Base(){}    virtualvoid func(int i=3)    {        cout<<"Base : "<<i<<endl;    public Base{public:    voidfunc(int i)    {        cout<<" Derived : "<<i<<endl;    }};

If you have:

    Base b;    Derived d;    d.func();  //能够通过编译吗

the answer is no .
When Func is called through the static binding of an object, the parameter value must be specified.

OK, so now there's this call:

    Basepbd = &d;    pbd->func();  //ok?

This is possible and runs the derived version of the function.
In other words, the output is:

Derived:3

The explanations in [1] are as follows:

If you call this function as an object, be sure to specify the parameter value.
Because of static binding, the function does not inherit default parameter values from its base.
However, if you call this function as a pointer or reference, you can specify no parameters, because dynamic binding sets the function to inherit the default parameter values from its base.

It's amazing, isn't it? The result of a function invocation is contributed by the default parameters of its base and the implementation of the derived.

Now, make a little change, if:

public Base{public:    voidfunc(int i=4)      //这里也指定了缺省参数    {        cout<<"Derived :"<<i<<endl;    }};

When there are:

    Base* pbd = &d;    pbd->func();  

What would be the result?
the output is 3, which is the default parameter inherited from base.

This demonstration is intended to illustrate the grammatical aspects of the problem. But from a design standpoint, this is unreasonable.
A number of different default parameters, causing the code to be difficult to read and behavior unclear.
What if we specify the same default parameters?

public Base{public:    voidfunc(int i=3)      //这里指定和base 一样的缺省参数    {        cout<<"Derived :"<<i<<endl;    }};

Also unreasonable, code duplication is an awkward question, if the default parameters in base are modified, then the default parameters in derived should be modified.
In fact, it is good to keep the version that is already in the beginning, but when you use it, you have to know clearly how it behaves.

Another alternative to the design is to use the NVI (non-virtual interface) approach : To make a public non-virtual function within the base class call the private virtual function, The latter can be redefined by the derived class.

Class base{Private:Virtual void Dofunc(inti) {cout<<"Base:"<<i<<endl; } Public:Virtual~Base(){}voidFuncintI=3) {Dofunc (i); }};class Derived: Publicbase{Private:Virtual void Dofunc(inti) {cout<<"Derived:"<<i<<endl; } Public:};

Finally, reiterate:
Never redefine an inherited default parameter value [1]

[References]
[1] Scott Meyers, Houtie. Effective C + +: 55 Effective practices for improving program technology and design thinking [M]. Electronic industry Press, 2011.
(clause 07: Declaring the virtual destructor for the polymorphic base class;
Article 09: Never call the virtual function in the construction and destruction process;
Article 34: Distinguish between interface inheritance and implementation inheritance;
Clause 37: Never redefine inherited default parameter values

Talk about virtual functions

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.