2012-10-11 1 views
0

У меня есть следующий простой классC++: как повторно использовать код в ковариантных типах возврата?

class base 
{ 
public: 
    int x; 
    base &set(int y) 
    { 
     x = y; 
     return *this; 
    } 
}; 

и хотите создать новую с дополнительной функциональностью, скажем, напечатать значение х. Так что я:

class derived : public base 
{ 
public: 
    void print() 
    { 
     cout << x << endl; 
    } 
}; 

В настоящее время в основной программе я хочу сделать что-то вроде

D.set(2).print(); 

, для которых, однако компилятор жалуется, что базовый класс не имеет элемент с именем «печать».

Если я пытаюсь использовать ковариантные типы возвращаемых и записать два класса в

class base 
{ 
public: 
    int x; 
    virtual base &set(int y) 
    { 
     x = y; 
     return *this; 
    } 
}; 

class derived : public base 
{ 
public: 
    derived &set(int y) 
    { 
     x = y; 
     return *this; 
    } 
    void print() 
    { 
     cout << x << endl; 
    } 
}; 

то оператор работает просто отлично, но я был вынужден переписать ту же самую функцию тела для «набор», в обоих классах , хотя единственное, что меняется, это тип возврата.

Если позже мне нужно изменить функциональность base :: set, мне придется пройти через все производные классы, чтобы изменить функцию «set» ... есть ли способы избежать этого? Заранее спасибо!

+0

Do вы на самом деле создаете «базовые» объекты или он должен быть «абстрактным» классом? – delnan

+0

Есть ли причина, по которой вы не хотите ставить 'print' на базу и переопределять по мере необходимости? –

+0

Почему вы не используете первые два примера классов и делаете печать виртуального метода в базовом классе? – evanmcdonnal

ответ

1

C++ работает, как вы говорите, и вы говорите в своем базовом классе set return base&, так что это то, что делает C++. Но для того, чтобы решить это, у вас есть много способов.

Сначала вы не должны использовать функцию virtual, чтобы переопределить ее в производном классе (обратите внимание, что виртуальный вызов немного медленнее, чем обычные вызовы).

Во-вторых, Вы можете обратиться к реализации базового класса, как base::set поэтому код будет следующим:

class base { 
    ... 
    base& set(int x) {...} 
}; 
class derived : public base { 
    derived& set(int x) { 
     return static_cast<derived&>(base::set(x)); 
    } 
}; 
+0

Yeap, это работает просто отлично, спасибо. Просто я хочу избежать бросков, я читаю в другом форуме, что многие из них означают, что перепроектирование в порядке ... – linuxfever

2

В зависимости от обстоятельств, вы можете быть в состоянии использовать CRTP:

template <class D> 
class base { 
    D& set(int x) { 
     …; 
     return *static_cast<D*>(this); 
    } 
}; 

class derived : base<derived> { … };