2
struct A{
    virtual void fun(){cout<<"A";}
};
struct B:public A{
    void fun(){cout<<"B";}
};
struct C:public B{
    void fun(){cout<<"C";}
};
int main() 
{
    C c;B b1;   
    A *a=&b1;
    a->fun(); //1
    B *b=&c;
    b->fun(); //2
    return 0;
}

In the above code B::fun() is getting converted to virtual function implicitly as I have made A::fun() virtual. Can I stop this conversion?

If not possible what are the alternatives to make the above code print "BB" ?

banarun
  • 2,305
  • 2
  • 23
  • 40

5 Answers5

1
  • If you do not want your derived classes to override the function then there is no reason why you should mark it virtual in base class. The very basis of marking a function virtual is to have polymorphic behavior through derived class function overidding.

Good Read:
When to mark a function in C++ as a virtual?

  • If you want your code to guard you against accidental overidding in derived classes.You can use the final specifier in C++11.
Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • No I actually want the base class to be virtual, but I don't want derived class to be virtual. – banarun Jul 02 '13 at 05:41
  • Doesn't that prevent overriding a function from the base class, rather than allowing you to override with a non-`virtual` function? – Tony Delroy Jul 02 '13 at 05:42
  • 1
    @banarun That defeats the purpose entirely, if only the base class is "virtual" then it isn't virtual. – Borgleader Jul 02 '13 at 05:43
  • @banarun: If you do not have a overidding behavior in derived class then Why would you want to mark the base class function to be `virtual`? It only makes sense if you have an overidding behavior in derived class. – Alok Save Jul 02 '13 at 05:44
  • I want base Class to be overridden by derived Class. But I don't want derived class to be overridden by another class that is derived from it. – banarun Jul 02 '13 at 05:46
  • @banarun then you use `final` in the first derived class. – juanchopanza Jul 02 '13 at 05:47
  • @banarun: You don't override classes. You override functions in those classes. overriding makes sense when you have polymorphic(*different*) behavior for a function with same name across base and derived class.Now if you don't need that there is no need of overriding at all. – Alok Save Jul 02 '13 at 05:48
1

Yes, if you want to explicitly call a function in a specific class you can use a fully qualified name.

b->A::fun();

This will call the version of fun() belonging to A.

Captain Obvlious
  • 19,754
  • 5
  • 44
  • 74
1

A virtual function is virtual in all derived classes. There is no way to prevent this.

(§10.3/2 C++11) If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf. For convenience we say that any virtual function overrides itself.

However, if you'd like to use the function that corresponds to the static, rather than the dynamic, type of a pointer (i.e., in your example, B::fun instead of C::fun, given that the pointer is declared as B*), then you can, at least in C++11, use the alias definition below to get access to the static (=compile-time) type:

template <typename Ptr>
using static_type = typename std::remove_pointer<Ptr>::type;

This is how you'd use this in main() (or anywhere else):

int main() 
{
  C c; B b1;   

  A *a = &b1;
  a->fun();

  B *b = &c;

  /* This will output 'B': */    
  b->static_type<decltype(b)>::fun();

  return 0;
}
jogojapan
  • 68,383
  • 11
  • 101
  • 131
1

The following achieves the observable behaviour you're asking for. In A, non-virtual fun() run virtual fun_() so the behaviour can be customised in B, but anyone calling fun() on a derived class will only see the non-polymorphic version.

#include <iostream>
using namespace std;

struct A{
    void fun(){fun_();}
  private:
    virtual void fun_() { cout << "A\n"; }
};

struct B:public A{
    void fun(){cout<<"B\n";}
  private:
    virtual void fun_() final { fun(); }
};

struct C:public B{
    void fun(){cout<<"C\n";}
};

int main()
{
    C c;B b1;
    A *a=&b1;
    a->fun(); //1
    B *b=&c;
    b->fun(); //2
    c.fun();    // notice that this outputs "C" which I think is what you want
}

If using C++03, you can simply leave out the "final" keyword - it's only there to guard against further unwanted overrides of the virtual behaviour in B-derived classes such as C.

(You might find it interesting to contrast this with the "Nonvirtual Interface pattern" - see C++ Coding Standards by Sutter and Alexandrescu, point 39)

Discussion

A having fun virtual implies that overriding it in derived classes is a necessary customisation ability for derived classes, but at some point in the derivation hierarchy the choice of implementation behaviours might have narrowed down to 1 and providing a final implementation's not unreasonable.

My real concern is that you hide A/B's fun() with C::fun... that's troubling as if they do different things then your code could be very hard to reason about or debug. B's decision to finalise the virtual function implies certainty that there's no need for such further customisation. Code working from A*/A&/B*/B& will do one thing, while wherever a C object's type is statically known, the behaviour may differ. Templated code is one place where C::fun may easily be called without the template author or user being very conscious of it. To assess whether this is a genuine hazard for you, it would help to know what the functional purpose of "fun" is and how implementation might differ between A, B and C....

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
0

If you declare the function in B like this

void fun(int ignored=0);

it will become an overload which will not take part in resolving virtual calls. Beware that calling a->fun() will call A::fun() though even if a actually refers to a B, so I would strongly advise against this approach as it makes things even more confusing than necessary.

Question is: What exactly is it that you want to achieve or avoid? Knowing that, people here could suggest a better approach.

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55