12

I have a very basic question concerning inheritance in C++:

class A
{
public:
  void foo() { print(); }
protected:
  void print() {}
};

class B : public A
{
protected:
  void print() { std::cout << "test" << std:: endl; }
};

Now the following code

B b;
b.foo();

doesn't print anything, so foo() obviously didn't call the newly defined print(). Is this only solvable by using virtual methods?

ph4nt0m
  • 948
  • 4
  • 10
  • 23
  • 3
    Question: why are you trying to avoid virtual methods? If you explain why, maybe we can help. – Mr Lister Jul 21 '12 at 14:22
  • 1
    The problem is that the class A (which I want to modify) is part of a library. So I have no real chance of making the method virtual if I don't want to modify the library itself. I think the easiest workaround will be your suggestion of copying the calling method into my subclass. – ph4nt0m Jul 21 '12 at 14:41

5 Answers5

11

Yes, you need to make print virtual in order for this to work. Otherwise, A::foo has no idea that descendants could provide alternative implementations of print, an happily calls A's version. Compiler may even inline the print inside foo at the time A's code is compiled, making the implementation in B completely irrelevant.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
6

In order for the derived class to override a function, the function must be declared virtual in the base class. That means that the function to call is chosen at run-time, when the function is called, according to the dynamic type of the object.

An alternative to overriding, if the derived type of each object is known at compile time, is to use the so-called "curiously recurring template pattern" (CRTP) to inject knowledge of the derived type into the base class (which must become a template to support this):

template <typename Derived> class A
{
public:
  void foo() { static_cast<Derived*>(this)->print(); }
};

class B : public A<B>
{
private:
  friend class A<B>; // assuming you don't want to make the function public
  void print() { std::cout << "test" << std:: endl; }
};
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • +1 for CRTP solution. (BTW, it is *"curiously **recurring (not recursive)** template pattern"*) – Nawaz Jul 21 '12 at 14:15
2

Yes you can virtual methods to make this example work, but you can also use CRTP.

Rickard
  • 7,239
  • 1
  • 18
  • 11
1

The answer to your question, "Is this only solvable by using virtual methods?" is: no, it is possible without using virtual methods.

All you need to do is copy the foo() method over to the body of B.

class B : public A
{
public:
  void foo() { print(); }
protected:
  void print() { std::cout << "test" << std:: endl; }
};

There.

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
  • In my humble opinion, here A is like a standard interface from the provider. The provider expects the consumer to override and provide a callback function that the consumer can use. – Ramakrishnan Kannan May 02 '16 at 20:35
  • @RamakrishnanKannan Yes, but according to the OP's comment to the question, they were in a situation where A was ineffective, yet A could not be changed to make the function virtual. – Mr Lister May 02 '16 at 20:51
0

Yes, you can't solve it without virtual methods or rewriting void foo()

because when A is compiling it doesn't know anything about B, so it can't call its method

RiaD
  • 46,822
  • 11
  • 79
  • 123