2012-02-15 20 views
19

Chcę, aby argument dla jednej z funkcji członka opcjonalne. Gdy nie podano argumentu, użyłby zmiennej składowej.Jak używać zmiennej składowej jako domyślnego argumentu w C++?

Jednakże, gdy próbowałem go skompilować pokazuje „błąd: Nieprawidłowe użycie non-statycznego członka danych«Object :: initPos»

Wystarczy, aby wyizolować problem, próbowałem zalegających typu int i skompilował się dobrze. Zastanawiam się, jaki jest problem z moim kodem i jak mogę użyć funkcji członka jako wartości domyślnej.

Dziękuję za pomoc!

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; 
}; 
+1

Twoje pytanie mnie tarło to jedno: http://stackoverflow.com/questions/9286801/valid-expressions-for-default-function-arguments –

Odpowiedz

30

wyrażenia Domyślny argument dla funkcji użytkownik może zależeć tylko na rzeczy, które są w klasy lub zasięgu globalnym. Domyślny argument również musi zostać określony w deklaracji metody (tj. W pliku nagłówkowym).

Aby obejść ten problem, trzeba 2 przeciążeń swojej metodzie moveTo. Jeden, który przyjmuje 1 argument, a drugi, który przyjmuje 2 argumenty. Metoda przyjmująca 1 argument wywołuje inną metodę, przekazując wartość, którą uważasz za domyślną.

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

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

Należy pamiętać, że po dokonaniu MoveTo(double) połączenia MoveTo(double, Point), pozwala pisać realizację MoveTo tylko raz, przy poszanowaniu zasady DRY.

+0

Dzięki! Wiem, że mogę to zrobić w ten sposób. Właśnie zastanawiałem się, czy jest krótszy sposób, aby to zrobić, na przykład uczynienie go domyślnym argumentem. Ale myślę, że to byłby jedyny sposób, żeby to zrobić. – tuzzer

+0

Więc co, jeśli zamiast jednego argumentu opcjonalnego, mam ich wiele? powiedzieć void Object :: MoveTo (podwójna prędkość, położenie punktu = initPos punkt A = m_a, punkt B = m_b, punkt c = m_c) wtedy nie będę musiał dokonać wielu funkcji ??? – tuzzer

+0

@MatthewChan: Niestety, tak. Zamiast podawać wiele argumentów, być może możesz zmienić projekt tak, aby użytkownik przekazał obiekt.Ten obiekt zawiera już rozsądne wartości domyślne, a użytkownik zmienia tylko te, które muszą być różne. Jeśli zdecydujesz się to zrobić w ten sposób, możesz być zainteresowany idiomem Method Chaining, aby ustawić wiele parametrów bardziej zwięzłych (http://en.wikipedia.org/wiki/Method_chaining). –

10

wartości domyślne nie są częścią prototypu, czyli są one rozstrzygane przez dzwoniącego, a nie przez samą funkcję. Po pierwsze, muszą być widoczne dla osoby dzwoniącej. Po drugie, nie mogą uzyskać dostępu do chronionych członków klasy. (Jestem prawie pewien, że nie można nawet używać publicznych elementów jako domyślnych, ale jestem zbyt zmęczony, aby to sprawdzić.)

Aby rozwiązać problem, użyj przykutych przeciążeń, co sugerują inne odpowiedzi.

+0

Dzięki. Próbowałem zmienić initPos na publiczny, ale jak powiedziałeś, to nadal nie zadziała. Więc czy możemy używać tylko stałej jako domyślnego argumentu (np. Nie funkcji członka, coś, co można wpisać)? – tuzzer

1

Można przeciążać element funkcyjny tak:

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

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

    MoveTo(speed, position); 
} 
+0

Niestety, jedyna praca wokół tego może wykonać pracę, wygląda brzydko :( – Argento

Powiązane problemy