3

Is overriding a pure virtual function with default arguments is good or bad?

class Base {
public:
    virtual int func(int i, int j = 10) = 0;
};

class Derived : public Base {
public:
    int func(int i, int j = 20) override;
};
  • 7
    Using different values for the default arguments will cause you nasty surprises. The actual value passed as default argument depends on what the call site knows of the type of the class. – Bart van Ingen Schenau Aug 4 '17 at 7:03
  • Wouldn't they cease to be pure virtual? In the sense that the default values are technically an implementation detail. – Berin Loritsch Aug 4 '17 at 13:48
  • What is the point of the default value in the Base? it would be less problematic if at least it's clear the default value is only in Derived – Adrian Maire Aug 8 '17 at 9:59
6

I would not venture to do this. At best, as @Bart van Ingen Schenau said, it will cause you nasty surprises. Furthermore, I would not even recommend using default parameters in virtual functions in the first place. If you want to have something like that, I suggest doing something like this:

class Base {
public:
    virtual int func(int i, int j) = 0;
    virtual int func(int i)
    {
        func(i, 10);
    }
};

class Derived : public Base {
public:
    int override func(int i, int j)
    {
        //Some override code
    }

    int override func(int i)
    {
        func(i, 20);
    }
};

You provide the basic funcionality with the most specific method, and provide easier methods to developers using your classes so they do not have to worry about default values for parameters. That way, you have bigger flexibility for intervention and you always know which method was called and how.

3

In principle, there's nothing wrong with overriding a function with default-arguments.

In practice, there's a huge chance that the override will contain different defaults, which is a huge source of confusion and consternation. Especially if those changed defaults lead to different behavior, the code now not only depending on the object but also knowledge at the call-site.

So, avoid overriding functions with defaults, and if you really must do so, be sure to provide the exact same defaults where the overridden function had defaults, though you can add additional ones.
Just having a non-overridable functions with defaults forwarding to an overridable protected function is an easy and rarely less efficient way to guard against getting that wrong.
(It's less efficient if the forwarder cannot be inlined for any reason.)


A different way to look at the issue is to see a function with defaults not as a single function, but as a whole bunch of overloads, only one of which is overridable and can have its address taken.

Having some of those overloads missing or doing something different would be a violation of the Liskov Substitution Principle for the static type (important for templates and code you write directly), just as having the overridden function violating the base-class-contract would be for both the static and dynamic type.

3

EDIT

It IS a terrible idea! Although you will call the overridden method, it will get the base class defaults

c# code

public class Base
{
    public virtual int Func(int i = 10)
    {
        Console.WriteLine("base");
        return i;
    }
}
public class Derived : Base
{
    public override int Func(int i = 20)
    {
        Console.WriteLine("derived");
        return i;
    }
}
Base b = new Derived();
Derived d = new Derived();
Console.WriteLine(b.Func());
Console.WriteLine(d.Func());

//ouput
derived
10
derived
20

c++ code

    #include <iostream>
#include <string>

class Base {
public:
    virtual int func(int i = 10)
    {
        std::cout << "base";
        return i;
    };
};

class Derived : public Base {
public:
    int  func(int i = 20) override
    {
        std::cout << "derived";
        return i;
    };
};

int main()
{
    Base* b;
    Derived d;
    b = &d;
    std::cout << b->func();  
    std::cout << d.func(); 
}
//output 
derived10derived20 

Crazy!

  • 1
    Care to prove this on an online compiler? Because as far as I can tell, the first is using the Base default. Because the defaults are inserted at the call site, based on the static type. – Jan Hudec Aug 4 '17 at 13:47
  • 2
    You know the question is about C++ and not C#? Aside from that, the result also doesn't seem to agree with what you say it should be... – Deduplicator Aug 4 '17 at 13:52
  • cpp.sh/56yir – Ewan Aug 4 '17 at 14:06
  • actually this is better cpp.sh/5bdmg my c++ is a bit rusty – Ewan Aug 4 '17 at 14:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.