2013-08-11 4 views
1

Просто мне нужно сделать так, как сказано в названии: вызвать дочерний статический метод из родителя. Проблема в том, что я не знаю имя дочернего класса в родительском, поскольку может быть несколько детей. Статический метод должен оставаться статичным. Например:C++: вызов дочернего статического метода из родителя

class A{ // parent class 
public: 
void process(){ 
    getData(); // <-- Problem 
} 
} 

class B: public A{ // child class 
static int getData(); 
} 

void main(){ 
B b; 
b.process(); 
} 

Одним из решений, которое приходит на ум, является наличие виртуального метода, который вызывает статический метод. Это не было бы очень хорошо, и это означало бы, я должен был бы реализовать метод для каждого ребенка, у меня есть:

class A{ // parent class 
virtual int getDataFromStaticMethod() = 0; 
public: 
void process(){ 
    getData(); // <-- Problem 
} 
} 

class B: public A{ // child class 
static int getData(); 
virtual int getDataFromStaticMethod(){ 
    return B::getData(); 
} 
} 

void main(){ 
B b; 
b.process(); 
} 

Но я действительно хочу это было возможно осуществить чисто виртуальный метод с помощью статического метода:

class A{ // parent class 
virtual int getData() = 0; 
public: 
void process(){ 
    getData(); // <-- Problem 
} 
} 

class B: public A{ // child class 
static int getData(); 
} 

void main(){ 
B b; 
b.process(); 
} 

Любые предложения?

Спасибо!

+0

Что произойдет, если два дочерних класса реализуют этот статический метод 'getData'? Какой из них вы хотите назвать? – yzt

+0

Рекомендация: Не используйте статическую функцию. Разница статической и нестатической функции заключается в том, что нестатическая функция может быть вызвана только тогда, когда известен экземпляр класса (этот указатель). В вашем случае кажется, что у вас всегда есть экземпляр, поэтому вы можете использовать нестатические функции. Или есть какая-то причина для статической функции, которую я пренебрегал? –

+0

@yzt Если у меня есть два класса B и C, которые оба наследуют A, я бы хотел вызвать статический метод B при вызове b.process() и статического метода C при вызове c.process(). Или вы имели в виду особый случай с множественным наследованием? – StackOverflowUser

ответ

2

Вы можете использовать шаблоны.

template<typename TChild> 
class A 
{ 
    typedef TChild child_type; 

public: 
    void process() 
    { 
     child_type::getData(); 
    } 
}; 

class B: public A<B> 
{ 
    static int getData(); 
}; 

class C: public A<C> 
{ 
    static int getData(); 
}; 

int main(int argc, char** argv) 
{ 
    B b; 
    b.process(); 

    C c; 
    c.process(); 
} 

Примечание:

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

class ABase 
{ 
    //any static state goes here 
public: 
    virtual int process() = 0; 
}; 

template<typename TChild> 
class A: public ABase 
{ 
    typedef TChild child_type; 

public: 
    int process() 
    { 
     child_type::getData(); 
    } 
}; 


class B: public A<B> 
{}; 


std::vector<ABase*> a_list; 
+0

Этот вид использования CRTP может быть подходящим, но если разваливается, если 'A' имеет какое-либо статическое состояние. Не так ли? – yzt

+0

Да. Если вы захотите получить статическое состояние для родительского класса, вы можете сделать дополнительный слой, то есть ABase, с A <>, полученным из ABase, и удерживать статическое состояние в ABase. – Gerald

+1

Большое спасибо, я поражен всеми ответами на мой вопрос, не ожидал такой обратной связи :) Я собираюсь с этим ответом, поскольку это то, что я искал. Спасибо! – StackOverflowUser

1

Предполагая, что подпись дочерних функций являются идентичным, можно инициализировать объект базового класса для хранения указателя на версию ребенка функции getData(), например:

class A { 
    int (*d_getData)(); 
protected: 
    explicit A(int (*getData)()): d_getData(getData) {} 
public: 
    void process() { 
     int data = (this->d_getData)(); 
     // ... 
    } 
}; 

Очевидно, что дочерние классы будут необходимо предоставить соответствующий аргумент конструктора:

class B: public A { 
    static int whatever(); 
public: 
    B(): A(&whatever) {} 
    // ... 
}; 

Это своего рода реализация одного объекта для переопределяемой виртуальной функции.

+0

Это то, о чем я думал и вначале, но это разваливается, когда более чем один класс наследует от 'A'. (Прочитайте комментарии к вопросу.) – yzt

+1

@yzt: Если существует несколько жизнеспособных функций, просто передайте тот, который вам нужен. Я не вижу причин, чтобы подход «разваливался» вообще! Существует много гибкости, и каждый производный * объект * может выбрать другую статическую функцию, которая будет вызываться при необходимости. –

+0

Правильно! Это может очень хорошо работать. Я думал, что 'd_getData' был * static *. Виноват. – yzt

1

Вы можете использовать виртуальные обертки вокруг статической функции. Например.

class A{ // parent class 
// don't make pure virtual if you don't want to define it in all child classes 
virtual int getData() { return 0 }; 
public: 
void process(){ 
    getData(); 
} 
} 

class B: public a{ // child class 
static int do_getData(); 
int getData() { return do_getData(); } 
} 
+0

Это то, что я описал во второй части моего вопроса. Это возможность, но это означает, что мне нужно будет реализовать метод getData у каждого ребенка. Спасибо хоть. – StackOverflowUser

+0

Вам нужно только реализовать 'getData()' у детей, которым это необходимо (т. Е. Иметь статический член, который им нужно вызвать). Я не знаю достаточно о вашей программе, чтобы ответить окончательно. –

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