How to use a member variable as a default argument in C++?

21,373

Solution 1

Default argument expressions for a member function can only depend on things that are in class or global scope. The default argument also has to be specified in the method's declaration (i.e. in the header file).

To get around this, you need 2 overloads of your MoveTo method. One that takes 1 argument, and another that takes 2 arguments. The method taking 1 argument calls the other method, passing along the value that you consider as the default.

void Object::MoveTo(double speed)
{
    MoveTo(speed, initPos);
}

void Object::MoveTo(double speed, Point position)
{
    // Everything is done here.
}

Note that when you make MoveTo(double) call MoveTo(double, Point), it allows you to write the implementation of MoveTo only once, thereby respecting the DRY principle.

Solution 2

Default values are not part of the prototype, i.e. they're resolved by the caller, not by the function itself. So firstly, they have to be visible to the caller. Secondly, they cannot access protected members of the class. (I'm pretty sure you can't even use public members as defaults, but I'm too tired to check.)

To solve the problem, use chained overloads as suggested in other answers.

Solution 3

You can overload your function member like that:

void Object::MoveTo(double speed, Point position) {
   ....
}

void Object::MoveTo(double speed) {
   Point position = this->initPos;

   MoveTo(speed, position);
}
Share:
21,373
tuzzer
Author by

tuzzer

Updated on July 09, 2022

Comments

  • tuzzer
    tuzzer almost 2 years

    I want to make an argument for one of the member functions optional. When no argument is provided, it would use an member variable.

    However, when I tried to compile it it shows "error: invalid use of non-static data member 'Object::initPos'"

    Just to isolate the problem, I tried defaulting an int type and it compiled fine. I wonder what is the problem with my code and how I could use a member function as default value.

    Thank you for your help!

    Object.h

    class Object
    {
        public:
           ...
           void MoveTo(double speed, Point position);
    
        protected:
           Point initPos; 
           Point currPos;
    
    };
    

    Object.c

    void Object::MoveTo(double speed, Point position = initPos)
    {
        currPos = postion;
    }
    

    Point.h

    class Point
    {
        ...
    
        private:
           double x;
           double y;
           double z; 
    };
    
  • tuzzer
    tuzzer over 12 years
    Thanks. I tried changing initPos to public, but as you said, it still won't work. So is it that we can only use constant as default argument (like not member function, something that you can type out)??
  • tuzzer
    tuzzer over 12 years
    Thanks! I do know that I can do it this way. I was just wondering if there's a shorter way to do it, such as making it a default argument. But I guess this would be the only way to do it.
  • tuzzer
    tuzzer over 12 years
    Then what if, instead of just one optional argument, I have many of them? say void Object::MoveTo(double speed, Point position = initPos, Point a = m_a, Point b = m_b, Point c = m_c) then won't I have to make many functions???
  • Emile Cormier
    Emile Cormier over 12 years
    @MatthewChan: Unfortunately, yes. Instead of passing many arguments, perhaps you can change the design so that the user passes an object. This object would already contain reasonable defaults, and the user only changes the ones that need to be different. If you decide to do it this way, you might be interested in the Method Chaining idiom to make setting multiple parameters more concise (en.wikipedia.org/wiki/Method_chaining).
  • tuzzer
    tuzzer over 12 years
    Just a question about Method Chaining then... If in C++, then you would do "return *this" right? Then won't that simply be making a copy of the instance of the object?? Then that instance won't actually change right? Like if I have a object called Car, and I have have an instance of Car called myCar. myCar.setColour(RED).setBrand(PORCHE).setYear(2012)
  • Emile Cormier
    Emile Cormier over 12 years
    *this is a reference to the current instance. If your setter signature is something like Car& setColor(Color c) (note the ampersand), then it will return a reference to the car, and not a copy. On the other hand, if the signature is Car setColor(Color c) (note the lack of an ampersand), then a copy of the car would be returned. For the method chaining thing to work, you therefore need to return a reference to the object.
  • Emile Cormier
    Emile Cormier over 12 years
    More method chaining info here: parashift.com/c++-faq-lite/ctors.html#faq-10.20. They call it Named Parameter idiom.
  • Amr Saber
    Amr Saber over 6 years
    unfortunately the only work around that could get the work done, looks ugly though :(
  • Arkajyoti Banerjee
    Arkajyoti Banerjee over 4 years
    they're resolved by the caller, not by the function itself : I see, that's the reason.
  • VHS
    VHS about 4 years
    This is a better answer than the accepted answer because you actually explained the problem.
  • User 10482
    User 10482 almost 4 years
    @Oliver Then why static data members are allowed as defaults? They are not any more visible than other data members (cause the object will exist when calling the member function). Or what about if static member is private?
  • Ted Lyngmo
    Ted Lyngmo almost 4 years
    @Argento What's ugly about it? It's quite common to have overloads calling other overloads.
  • Amr Saber
    Amr Saber almost 4 years
    @TedLyngmo I am used to other programming languages, like (JS, Python, Kotlin, etc...) compared to them, and considering that C++ does already have syntax for function's default value, this is an ugly workaround and not something that is supported by default like other languages. Nevertheless, it's a matter of personal opinion after all.
  • Ted Lyngmo
    Ted Lyngmo almost 4 years
    @Argento Do the languages you mention accept defaults via an implicit *this (or the language equivalent)?
  • Amr Saber
    Amr Saber almost 4 years
    @TedLyngmo In Kotlin and JS Yes they do, not sure about python haven't used its OOP heavily before. so the mentioned example will become something like MoveTo(speed, position = initPos) { ... }