Skip to content

Latest commit

 

History

History
115 lines (86 loc) · 2.68 KB

mar19_private_virtuals.md

File metadata and controls

115 lines (86 loc) · 2.68 KB

I had no idea you could override a private function. I assumed that since you couldn't call it, then you couldn't override it...

Turns out private and virtual are orthogonal. It can be really useful. Virtual functions form a relationship between base and derived classes. This need not be the same as the relationship between client code and the base interface.

And in fact probably often (always?) should be separate.

One common "code smell" example is cases where the base <-> derived interface includes comments like "make sure derived::foo() calls base::foo() first". Whenever you see that, you should think "how can I enforce that better than with a comment". The answer is typically make base::foo() (that clients call) non-virtual, have it do whatever needs to be done first, and then have it call a virtual base <-> derived interface function (ie vfoo()) for the derived part.

Whoops Non-virtual Idiom
class Base
{
public:
    // Clients call this when
    // they need to resize blah blah.
    // Note: if you override this,
    // make sure you call Base::resize() first!
    virtual void resize()
    {
        stuff();
        thatMust();
        happen();
        
        
    }
    
    
    
};

class Derived : public Base
{
    // whoops, where's the call to Base::resize?
    void resize() override
    {
        // measure twice, cut once
        measure();
        measure();
        cut();
    }
};
class Base
{
public:
    // Clients call this when
    // they need to resize blah blah.


    void resize()  // NON VIRTUAL!
    {
        stuff();
        thatMust();
        happen();
        
        onResize(); // virtual
    }
    
private:
    virtual void onResize() { }
};

class Derived : public Base
{

    void onResize() override
    {
        // measure twice, cut once
        measure();
        measure();
        cut();
    }
};

Clients should not call onResize(), therefore it can be, and should be, private (or maybe protected, but protected is often a code smell as well, ... but that's another story).


This pattern is sometimes called the "Non-virtual idiom" and I learned it from Herb Sutter's Guru of the Week http://www.gotw.ca/publications/mill18.htm

I guess the original pattern is Template Method Pattern https://en.wikipedia.org/wiki/Template_method_pattern (note the "template" in the name does not refer to C++ templates). Although most other languages don't allow overriding private methods, and/or having non-virtual methods, so I find there is extra control/strictness in C++'s version.