solarflare
solarflare

Reputation: 441

Default value parameter in pure virtual function

I submitted some code as:

Abstract class:

virtual void someFunction(std::vector<someObject*> & iObject) = 0;
virtual void someFunction(std::vector<someObject*> & iObject, bool aSwitch) = 0;

The first function was existing, I added the second to avoid having a default value parameter in a pure method.

Header in the derived class:

virtual void someFunction(std::vector<someObject*> & iObject);
virtual void someFunction(std::vector<someObject*> & iObject, bool aSwitch = false);

Usage as expected:

someFunction(std::vector<someObject*> & Object);

or

someFunction(std::vector<someObject*> & Object, true);

someFunction as it was - already existed, I added the switch. It works well but I'm confused.

I have a code reviewer saying I should include a default value in the pure virtual function to avoid the two function signatures. I remember reading that default values in pure virtuals are not a good idea but I can't argue a valid point and the articles dont seem clear as to why.

Would it cause ambiguity if I added the default value and if so would I still need the default value in the derived virtual method?

Could I just add the default value in the pure virtual function and do away with the first function in the derived class header? What is the best practice here?

Upvotes: 2

Views: 1950

Answers (1)

Christophe
Christophe

Reputation: 73376

Default arguments in general

The default arguments for functions are not bound to the function itself, but to the calling context: defaults declared for for the function in the scope in which it is called will be used (See C++ standard, [dcl.fct.default]). For example:

void f(int a=1);     // forward declaration with a default value for the compilation unit
void f(int a)        // definition 
{
    cout<<a<<endl; 
}
void g() {
    void f(int a=2);  // declaration in the scope of g
    f();
}
int main() {
    f();            // uses general default => 1
    g();            // uses default defined in g => 2
    return 0;
}

Default arguments for virtual functions

This logic applies to all functions, so also the pure virtual functions. The only thing, is that the function declaration (and its defaults) that is considered is the one of the object class known by the compiler. So the same function of the same object may have different default arguments, depending on the object type used to invoke it. For example:

struct A {
    virtual void f(int a=1) = 0;    
};
struct B:A {
    void f(int a) override ;     
};
struct C:A {
    void f(int a=2) override ;     
};

void B::f(int a)        // definition 
{
    cout<<"B"<<a<<endl; 
}
void C::f(int a)        // definition 
{
    cout<<"C"<<a<<endl; 
}

int main() {
    B b; 
    C c; 
    A *x=&c, *y=&b;    // points to the same objects but using a polymorphic pointer
    x->f();  // default value defined for A::f() but with the implementation of C ==> C1   
    y->f();  // default value defined for A::f() but with the implementation of B ==> B1
//  b.f();  // default not defined for B::f() so cannot compile   
    c.f();  // default value defined for C::f(); ==> C2
}

Good to know

  • Default arguments don't alter the signature of the function. It's still the same function.
  • Different default arguments don't affect the ODR rule. So you could use different default values in different compilation units, and it would still be the same function.
  • The default arguments are provided by the caller, not by the function itself
  • If different default arguments are defined for base and derived classes, you need to be extremely careful, since different defaults might be used depending on how you call the function.

Upvotes: 3

Related Questions