Why is the “virtuality” of methods implicitly propagated in C++?

南笙酒味 提交于 2019-11-30 17:45:15

C++11 added the contextual keyword final for this purpose.

class VectIterator : public Iterator<T>
{
public:
    T& next() final { ... }
    ...
};

struct Nope : VecIterator {
    T& next() { ... } // ill-formed
};

The simple snswer is : Don't mix concrete and abstract interfaces! The obvious approach in you example would be the use of a non-virtual function next() which delegates to a virtual function, e.g., do_next(). A derived class would override do_next() possibly delegating to a non-virtual function next(). Since the next() functions are likely inline there isn't any cost involved in the delegation.

wiggily

In my opinion one of the good reasons for this propagation is the virtual destructors. In C++ when you have a base class with some virtual methods you should define the destructor virtual. This is because some code may have a pointer of base class which is actually pointing to the derived class and then tries to delete this pointer (see this question for more detail). By defining the destructor in base class as vritual you can make sure all pointers of base class pointing to a derived class (in any level of inheritance) will delete properly.

I think the reason is that it would be really confusing to remove virtuality partway through an inheritance structure (I have an example of the complexity below).

However if your concern is the micro-optimization of removing a few virtual calls then I wouldn't worry. As long as you inline the virtual child method's code, AND your iterator is passed around by value and not reference, a good optimizing compiler will already be able to see the dynamic type at compile time and inline the whole thing for you in spite of it being a virtual method!

But for completeness, consider the following in a language where you can de-virtualize:

class A
{
public:
    virtual void Foo() { }
};

class B : public A
{
public:
    void Foo() { } // De-virtualize
};

class C: public B
{
public:
    void Foo() { } // not virtual
};

void F1(B* obj)
{
    obj->Foo();
    static_cast<A*>(obj)->Foo();
}

C test_obj;
F1(test_obj);   // Which two methods are called here?

You could make rules for exactly which methods would get called but the obvious choice will vary from person-to-person. It's far simpler to just propagate virtualness of a method.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!