2009-06-05 2 views
3

У меня есть что-то вроде этого:Принудительно статический метод перегрузки в дочернем классе в C++

class Base 
{ 
    public: 
    static int Lolz() 
    { 
     return 0; 
    } 
}; 

class Child : public Base 
{ 
    public: 
    int nothing; 
}; 

template <typename T> 
int Produce() 
{ 
    return T::Lolz(); 
} 

и

Produce<Base>(); 
Produce<Child>(); 

возвращают 0, что, конечно, правильно, но нежелательно. Есть ли в любом случае принудительное применение явного объявления метода Lolz() во втором классе или, может быть, ошибка времени компиляции при использовании Produce<Child>()?

Или это плохой дизайн OO, и я должен сделать что-то совершенно другое?

EDIT:

То, что я в основном пытаются сделать, это сделать что-то вроде этой работы:

Manager manager; 

manager.RegisterProducer(&Woot::Produce, "Woot"); 
manager.RegisterProducer(&Goop::Produce, "Goop"); 

Object obj = manager.Produce("Woot"); 

или, в более общем плане, внешний абстрактный завод, который не знает типы создаваемых объектов, так что новые типы могут быть добавлены без написания большего количества кода.

+0

Можете ли вы предоставить подробную информацию о контексте? Похоже, ваше программирование - своего рода заводская штуковина. – diapir

+1

Если метод Produce вашего Менеджера все равно возвращает указатель на базовый класс, то в чем смысл использования шаблонов? Вы можете просто определить свой метод RegisterProducer следующим образом: void RegisterProducer (Object * (* pfnProduce)(), const char * pName) –

ответ

6

Есть два способа избежать этого. Собственно, это зависит от того, что вы хотите сказать.

(1) Изготовление продукта() в качестве интерфейса базового класса.

template <typename T> 
int Produce() 
{ 
    return T::Lolz(); 
} 
class Base 
{ 
    friend int Produce<Base>(); 

protected: 
    static int Lolz() 
    { 
     return 0; 
    } 
}; 

class Child : public Base 
{ 
public: 
    int nothing; 
}; 

int main(void) 
{ 
    Produce<Base>(); // Ok. 
    Produce<Child>(); // error :'Base::Lolz' : cannot access protected member declared in class 'Base' 
} 

(2) Использование специализации шаблонов.

template <typename T> 
int Produce() 
{ 
    return T::Lolz(); 
} 
class Base 
{ 
public: 
    static int Lolz() 
    { 
     return 0; 
    } 
}; 

class Child : public Base 
{ 
public: 
    int nothing; 
}; 

template<> 
int Produce<Child>() 
{ 
    throw std::bad_exception("oops!"); 
    return 0; 
} 

int main(void) 
{ 
    Produce<Base>(); // Ok. 
    Produce<Child>(); // it will throw an exception! 
} 
+0

Спасибо! Номер 1 был именно тем, что я искал. – GhassanPL

1

C++ не поддерживает виртуальные статические функции. Подумайте о том, что должно было бы понравиться vtable, чтобы поддержать это, и вы поймете, что это не так.

2

Невозможно переопределить статический метод в подклассе, его можно скрыть. Также нет ничего аналогичного абстрактному методу, который заставил бы подкласс дать определение. Если вам действительно нужно различное поведение в разных подклассах, вы должны сделать Lolz() метод экземпляра и переопределить его как обычно.

Я подозреваю, что вы находитесь рядом с проблемой дизайна здесь. Одним из принципов объектно-ориентированного проектирования является принцип подстановки. В основном это говорит о том, что если B является подклассом A, тогда он должен быть действительным для использования B, где бы вы не могли использовать A.

0

Насколько я понимаю ваш вопрос, вы хотите отключить статический метод из родительского класса , Вы можете сделать что-то подобное в производном классе:


class Child : public Base 
{ 
public: 
    int nothing; 
private: 
    using Base::Lolz; 
}; 

Теперь Child::Lolz становится частным. Но, конечно, гораздо лучше исправить дизайн :)

Смежные вопросы