Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to not inherit "virtualness" of a function in a subclass?

Tags:

c++

virtual

Is it possible in C++ to have a class override a virtual function, but only have virtual dispatch when the function is called through the superclass (ie. not when it is called on something statically typed as the subclass)? I know this isn't what happens, but is there any way to achieve something close?

The reason for wanting this is that I have two classes which both expose a flush() function. The vast majority of the time in my program, I am calling flush() directly on a subclass object that I know the type of, so I don't need virtual dispatch. However I want to add a superclass into the mix so that very infrequently I can pass a reference to an instance of either one of the classes into a doSomethingThenFlush() function, which would call flush() virtually.

I know I could use templates instead of virtual functions, and I know I could have two different functions (eg. flushVirtual() which just called flushNonVirtual(), and call flushNonVirtual() everywhere I don't need virtual dispatch). But these both seem a bit like throwing code at a problem which is largely syntactical. Is there any more elegant way to achieve this?

Perhaps more importantly, does anyone know why virtualness is inherited in C++?

struct Base
{
  virtual ~Base(){}
  virtual void func();
};

struct Derived : public Base
{
  void func(){}
};

void callVirtually(Base &base)
{
  base.func();//this will use virtual dispatch
}

void callStatically(Derived &derived)
{
  derived.func();//I don't want/need this to use virtual dispatch
}

int main()
{
  Derived derived;
  callVirtually(derived);
  callStatically(derived);
}
like image 906
Karu Avatar asked Aug 18 '11 04:08

Karu


People also ask

Is it mandatory to override virtual function?

It is not mandatory for the derived class to override (or re-define the virtual function), in that case, the base class version of the function is used. A class may have virtual destructor but it cannot have a virtual constructor.

Is it mandatory to override virtual function in derived class * Yes No?

Yes, Its correct that a Derived class has to OVERRIDE the function which is Pure Virtual in the Parent Class.

Is virtual keyword needed in base class?

Adding the "virtual" keyword is good practice as it improves readability , but it is not necessary. Functions declared virtual in the base class, and having the same signature in the derived classes are considered "virtual" by default.

Can a derived class have a virtual function?

A virtual function is a member function that you expect to be redefined in derived classes. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function.


4 Answers

Virtualness is inherited because you don't know if someone is going to derive further from your Derived. Someone could just as well make a MoreDerived which could be passed to a function expecting a Derived&, and they'd be sad when they found that it was Derived's versions of all your virtual functions were bieng called instead of MoreDerived's.

If you mean that you won't ever inherit from Derived so you don't want to pay for a virtual function call, then you're out of luck, because C++ provides no way to promise that you won't ever inherit from a class, which would be necessary to do what you are wanting.

like image 162
Seth Carnegie Avatar answered Nov 15 '22 21:11

Seth Carnegie


In C++03, no.

As others said, it is a compiler optimization (and a frequently used one) to de-virtualize he call whenever it can assess that the runtime type of the object.

However, in C++0x we get two new keywords: override and final and both can be applied to member functions (final can also be applied to a class).

  • override: specify that this function overrides a virtual function in a base class, useful to get warned when this is not the case
  • final: specify that this function (virtual) cannot be overriden in children classes.

Your class would thus become:

struct Derived : public Base
{
  void func() final {}
};

Note: using final does not mandate that the compiler devirtualize function calls (from the Standard point of view), but any compiler worth its salt should do so.

like image 28
Matthieu M. Avatar answered Nov 15 '22 21:11

Matthieu M.


In your specific example, if callStatically gets inlined, the compiler will probably avoid the virtual function dispatch because it can see the object's actual type (because it is a local variable).

Probably your compiler can also avoid a virtual dispatch for cases like this:

class Foo {
public:
    callStatically() { d.func() }
private:
    Derived d;
};

The compiler is likely to perform this optimization whether or not callStatically is inlined, because it can see the actual type of the variable member.

But to my knowledge, there is no way to force the compiler to bypass the virtual call in general.

like image 35
Nemo Avatar answered Nov 15 '22 20:11

Nemo


The answer lies in your question.

derived.func();  // no virtual dispatch

When you call a virtual function using object, there is no virtual dispatch. It calls the function using the static-type of the object.

virtual function comes into the picture only when you try to call a function using a pointer or a reference.

Edit: In your updated question, you are using Derived& to call func(). Calling by reference will make sure that virtual dispatch happens. So there is no language facility (like final in Java), which will stop virtual dispatch.

like image 32
iammilind Avatar answered Nov 15 '22 19:11

iammilind