1

Consider the following:

// ConsoleApplication1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <string>
#include <iostream>

using namespace std;

class Foo {
public:
    // NVI
    bool method() {
        cout << "Foo::method" << endl;
        return method_impl();
    }

    // Why not do this instead?
    //virtual bool method() final {
    //    cout << "Foo::method" << endl;
    //    return method_impl();
    //}

private:
    virtual bool method_impl() = 0;
};

class Bar : public Foo {
public:
    // What stops someone from doing this hiding the Foo::method identifier?
    // Uncomment the below and see how the console output is instead Bar::method and then method_impl

    //bool method() {
    //    cout << "Bar::method" << endl;
    //    return method_impl();
    //}

private:
    virtual bool method_impl() override {
        return true;
    }
};


int _tmain(int argc, _TCHAR* argv[]) {
    Bar bar = Bar();

    cout << bar.method() << endl;

    return 0;
}

As you can see above, the Foo class is trying to follow the NVI pattern with the Foo::method() member function.

What prevents a child class, in this case Bar, from hiding the Foo::method() with Bar::method()? I tried it and I guess nothing. If you uncomment Bar::method(), the console application does indeed go down the Bar implementation of method() which makes total sense.

Which begs the question, why not use virtual final to disallow name hiding of that method in a child class? Example provided in the Foo class.

Thanks

  • For polymorphism to work you usually use *pointers* or *references* to the base class. If the child-class hides the `method` function, it doesn't matter in that case, since it will always be the base-class function being called. In your example, try to do e.g. `Foo* bar = new Bar;` instead, and see what happens. – Some programmer dude Oct 01 '17 at 22:25
  • Yep, I totally get that for polymorphism I might use a factory that only dishes out the parent interface but say for instance it's a use case where multiple levels of derived objects are validly usable by the application or that the application writer is intended to extend an interface (or provide it's own concrete implementation), how do you by design prevent accidental (perhaps even malicious in the case of a middleware) name hiding. – azy.development Oct 01 '17 at 22:35
  • If you have a factory-function which can return a pointer to any base class (perhaps through templates) then there is no way you can protect against child-classes hiding base-class functions. You have to trust the users of the code to not do bad things (which leads to the whole [trusting trust](https://www.google.se/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0ahUKEwjuzavHv9DWAhWHJZoKHQpND6AQFggnMAA&url=https%3A%2F%2Fwww.ece.cmu.edu%2F~ganger%2F712.fall02%2Fpapers%2Fp761-thompson.pdf&usg=AOvVaw3u2BYjJMPpFXNpO1FIKxgZ) issue). – Some programmer dude Oct 01 '17 at 22:43
  • 1
    Well, you could make it virtual final effectively forbidding that function signatures (including args of course) in any further child classes. As a compile time check its also super helpful to prevent accidental name hiding. It does incur a vtable overhead but worthwhile I'd think. In the code above, if you use the virtual final version in Foo and uncomment the Bar attempted override, the compiler will complain as it should. – azy.development Oct 01 '17 at 22:52
  • If you want to avoid accidental hiding, you may want to put "virtual final" in debug builds only. – geza Oct 01 '17 at 23:35
  • That's what I'm suggesting. More specifically, I'm wondering if there's any reason I haven't thought of to *not* put virtual final. – azy.development Oct 02 '17 at 00:04
  • What I meant is debug build has virtual final, but release has not. So you can catch accidental override, and release build still optimal because of no unnecessary virtuals. Maybe compiler writers can optimize away virtual, if virtual final doesn't override. – geza Oct 02 '17 at 01:01
  • Oh yes, I agree you can do that. Might make managing debug/release builds a bit messy though. So it seems no one has an opinion against virtual final instead of the common NVI pattern is worse (other than that vtable indirection)? – azy.development Oct 02 '17 at 01:03
  • Where is the virtual inheritance? – curiousguy Oct 03 '17 at 20:26
  • @curiousguy Can you elaborate? – azy.development Oct 05 '17 at 06:30
  • Why do you put a virtual inheritance tag on your question if there is no such thing in your code? – curiousguy Oct 06 '17 at 10:56
  • Oh I see. Oops, that is not the tag I was looking for. I wanted 'inheritance' and 'virtual' but not 'virtual inheritance'. Fixed. – azy.development Oct 06 '17 at 15:35

0 Answers0