10

It seems that it is good to make the virtual methods private in order to separate the interfaces for following two clients - 1. clients that instantiate an object and call the method 2. clients that derive from the class and may want to override the method. Simply put - the first client does not need to know if a method is virtual. He will call the base class public non-virtual method which in turn will call the private virtual method. See code below for example.

Now in the case where the virtual method needs to super-message its base class' corresponding virtual method such as say a Save method - which has to pass through all virtual methods in the chain of inheritance in order to save data corresponding to each level of derivation - we have no option but to use a protected virtual method - unless there is a way to guarantee saving of data at all levels of derivation without using super messaging (there is none that I know).

I would like to know if above reasoning correct.

Make sure you use the scroll to see the entire code.

#include <iostream>
using namespace std;

class A {

    string data;    

protected:

    virtual void SaveData()= 0;

public:

    A():data("Data of A"){}

    void Save(){
        cout << data << endl;        
        SaveData();
    }
};

class B : public A {

    string data;

protected:

    virtual void SaveData() { cout << data << endl;}

public:

    B():data("Data of B") {}

};

class C : public B {

    string data;
protected:

    virtual void SaveData() {
        B::SaveData();
        cout << data << endl;
    }

public:

    C():data("Data of C") {}
};


int main(int argc, const char * argv[])
{
    C c;
    c.Save();

    return 0;
}
MMR
  • 101
  • 1
  • 1
  • 4

3 Answers3

12

Yes, if you need to call the SaveData of another class, it needs to be accessible from that class - so public or protected.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
7

You are exactly right:

  • NVI (Non-Virtual Interface) requires that virtual methods not be public
  • Calling the base class method requires that it not private

therefore protected is the obvious solution, at least in C++03. Unfortunately it means you have to trust the derived class developer not to forget to call "super".


In C++11, you can use final to prevent a derived class from overriding a virtual method; it means though that you are forced to introduce a new hook, example:

class Base {
public:
    void save() {
        // do something
        this->saveImpl();
        // do something
    }
private:
    virtual void saveImpl() {}
};

class Child: public Base {
private:
     virtual void saveImpl() final {
         // do something
         this->saveImpl2();
         // do something
     }
     virtual void saveImpl2() {}
};

Of course, there is the trouble of having to come up with a new name each and every time... but at least you are guaranteed that Child::saveImpl will be called because none of its children can override it.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • why does NVI require that the virtual function be non-public? – Rich Sep 15 '15 at 03:21
  • @Rich: In C++, when a derived class overrides a method, it completely replaces it; NVI is there to ensure that the base class retains some amount of control (for example, taking a lock, checking invariants, ...) which is incompatible with a virtual method. For more information, see https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface – Matthieu M. Sep 15 '15 at 06:16
  • Thanks for the link and I think I understand the moral behind this idiom. I just don't quite understand when you say NVI *requires* the virtual method not be `public`. Besides the guideline of separating client (public) interface from implementation (non public) interface, I can't see why a public virtual prevents NVI from working. Is it disastrous to declare saveImpl() public in the above example? – Rich Sep 15 '15 at 17:27
  • @Rich: `saveImpl` being `final` (and thus no longer virtual), no :) – Matthieu M. Sep 15 '15 at 17:44
  • @MatthieuM. Oh I missed the `final` part. But your solution was particular to what the OP wants, namely forcing propagation and handling on each level of derivation. In a traditional NVI idiom, where any derived classes can override `saveImpl`, why can't `saveImpl` be public, except it goes against OO principles of separating interface from implementations. – Rich Sep 15 '15 at 18:04
  • @Rich: Actually, I missed something. The goal of making `saveImpl` private is to *ensure* that it is only ever called through `save`. Imagine that `save` is taking a lock, calling `saveImpl` without taking that lock could be disastrous! – Matthieu M. Sep 15 '15 at 18:08
2

It's difficult to tell what you're asking, but from the example, you do not need to make the method protected. It actually can be private. For details about the subtleties see this post: What is the point of a private pure virtual function?.

So long as you're not calling the private member from derived class (or outside classes), you're ok. Overriding of private members is ok. It does sound quite naughty and wrong that you can override your parent's privates, but in c++ you're allowed to do this.

The following should be ok:

#include <iostream>
using namespace std;

class A {

    string data;    

private:

    virtual void SaveData()= 0;

public:

    A():data("Data of A"){}

    void Save(){
        cout << data << endl;        
        SaveData();
    }
};

class B : public A {

    string data;

private:

    virtual void SaveData() { cout << data << endl;}

public:

    B():data("Data of B") {}

};
Community
  • 1
  • 1
thang
  • 3,466
  • 1
  • 19
  • 31