2013-09-09 4 views
0

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

Например:

class AbstractCoolThingDoer 
{ 
    void dosomethingcool() = 0; // now if you implement this class 
             // you better do this 
} 

class CoolThingDoerUsingAlgorithmA: public AbstractCoolthingDoer 
{ 
    void dosomethingcool() 
    { 
     //do something cool using Algorithm A 
    } 
} 

class CoolThingDoerUsingAlgorithmB: public AbstractCoolthingDoer 
{ 
    void dosomethingcool() 
    { 
     //do the same thing using Algorithm B 
    } 
} 

Теперь я хотел бы сделать coolthing без деталей, как coolthing будет сделано. Так что я хотел бы сделать что-то вроде

AbstractCoolThingDoer:dosomethingcool(); 

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

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

РЕДАКТИРОВАТЬ: Не уверен, что я понял, чего я пытаюсь достичь. У меня есть 3 критерии, которые я ищу, чтобы удовлетворить

  1. библиотека, которая использует abstractcoolthingdoer и не должны быть переписаны когда-либо, даже если другой coolthingdoer написано, что библиотека никогда не слышал.

  2. Если вы попытаетесь написать coolthingdoer, который не соответствует требуемой структуре, исполняемый файл, который использует библиотеку, не будет компилироваться.

  3. coolthingdoer имеет некоторые статические функции, которые требуются.

Я, вероятно, преследую плохой дизайн, поэтому, пожалуйста, укажите мне лучший вариант. Мне нужен завод?

+0

И как именно будет 'реализация CoolThingDoerUsingAlgorithmB' в забрать? – juanchopanza

+0

Вам разрешено предоставлять реализации для чистых виртуальных функций.Таким образом, обеспечить (вне очереди) реализацию 'AbstractCoolThingDoer :: dosomethingcool', а производные классы по-прежнему будут вынуждены переопределять виртуальную функцию, но те, которые не хотят делать * холодную вещь * по-разному, могут по-прежнему звонить реализация базового класса по умолчанию явно в пределах их тела. – Praetorian

+0

Возможно, в этом случае вы можете просто определить указатель на «void dosomethingcool()» и объявить его членом в AbstractCoolThingDoer? – vasylz

ответ

2

Может быть, что-то вроде это поможет (см ideone.com example):

#include <iostream> 

class A 
{ 
protected: 
    virtual void do_thing_impl() = 0; 
public: 
    virtual ~A(){} 
    static void do_thing(A * _ptr){ _ptr->do_thing_impl(); } 
}; 

class B : public A 
{ 
protected: 
    void do_thing_impl(){ std::cout << "B impl" << std::endl; } 
}; 

class C : public A 
{ 
protected: 
    void do_thing_impl(){ std::cout << "C impl" << std::endl; } 
}; 

int main() 
{ 
B b_; 
C c_; 

A::do_thing(&b_); 
A::do_thing(&c_); 

return (0); 
} 

EDIT: Мне кажется, что ОП не требуется время выполнения полиморфизма, а время компиляции полиморфизма без необходимости экземпляра класса (использование функции static, когда реализация скрыта в производных классах, не требуется никаких экземпляров). Надеюсь, что следующий код помогает решить (example on ideone.com):

#include <iostream> 

template <typename Derived> 
struct A 
{ 
    static void do_thing() { Derived::do_thing(); } 
}; 

struct B : public A<B> 
{ 
    friend A<B>; 
protected: 
    static void do_thing() { std::cout << "B impl" << std::endl; } 
}; 

struct C : public A<C> 
{ 
    friend A<C>; 
protected: 
    static void do_thing() { std::cout << "C impl" << std::endl; } 
}; 

int main() 
{ 
A<B>::do_thing(); 
A<C>::do_thing(); 

return (0); 
} 

EDIT # 2: Для того, чтобы заставить неудачу во время компиляции в случае, если пользователь не соответствует требуемому шаблону, здесь slight modification at ideone.com:

#include <iostream> 

template <typename Derived> 
struct A 
{ 
    static void do_thing() { Derived::do_thing_impl(); } 
}; 

struct B : public A<B> 
{ 
    friend A<B>; 
protected: 
    static void do_thing_impl() { std::cout << "B impl" << std::endl; } 
}; 

struct C : public A<C> 
{ 
    friend A<C>; 
protected: 
    static void do_thing_impl() { std::cout << "C impl" << std::endl; } 
}; 

struct D : public A<D> 
{ 
friend A<D>; 
}; 

int main() 
{ 
A<B>::do_thing(); 
A<C>::do_thing(); 
A<D>::do_thing(); // This will not compile. 

return (0); 
} 
+0

И очевидный последующий вопрос к ОП, почему он статичен в первую очередь? Вам нужно действовать на экземпляр, так почему бы просто не использовать обычную старую нестационарную функцию-член? – juanchopanza

+0

@juanchopanza Я точно не знаю. Может быть, автор 'class A' хочет сделать некоторую общую предварительную/прошлую обработку в' static' функции? – lapk

+0

Я предполагаю, что вы оба говорите, что в общем случае нужно выбрать либо 1) создать объект для вызова его функций, даже если это не интуитивно понятно или 2) использовать что-то помимо наследования, чтобы убедиться, что классы аддона имеют требуемую структуру? – OldMcFartigan

0

Это выглядит как подходящее место для реализации bridge pattern. Возможно, это то, чем вы (бессознательно) готовы достичь. Короче говоря, вы указываете интерфейс и его реализации, а затем вызываете свой метод do_thing, в свою очередь, вызываете реализацию по указателю на класс реализации.

C++ example

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