C++: Overriding a protected method which is called by another method

13,601

Solution 1

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.

Solution 2

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; }
};

Solution 3

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

Solution 4

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.

Share:
13,601

Related videos on Youtube

ph4nt0m
Author by

ph4nt0m

Updated on August 30, 2022

Comments

  • ph4nt0m
    ph4nt0m over 1 year

    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?

    • Mr Lister
      Mr Lister almost 12 years
      Question: why are you trying to avoid virtual methods? If you explain why, maybe we can help.
    • ph4nt0m
      ph4nt0m almost 12 years
      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.
  • Nawaz
    Nawaz almost 12 years
    +1 for CRTP solution. (BTW, it is "curiously recurring (not recursive) template pattern")
  • Ramakrishnan Kannan
    Ramakrishnan Kannan almost 8 years
    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.
  • Mr Lister
    Mr Lister almost 8 years
    @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.