Я пытаюсь написать абстрактный класс на С ++ и не могу понять, как требовать от разработчиков этого класса статической функции.
Например:
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
}
}
Теперь я хотел бы сделать что-нибудь интересное без подробностей того, как это делается. Так что я хотел бы сделать что-то вроде
AbstractCoolThingDoer:dosomethingcool();
без необходимости знать, как это делается, но для этого требуется виртуальная и статическая функция, что, конечно, является противоречием.
Логическое обоснование состоит в том, что CoolThingDoerUsingAlgorithmB может быть написан позже, и, надеюсь, не нужно будет переписывать программу, которая нуждается в классных вещах.
РЕДАКТИРОВАТЬ: Не уверен, что я был ясно о том, что я пытаюсь сделать. У меня есть 3 критерия, которые я ищу, чтобы удовлетворить
Библиотека, которая использует abstractcoolthingdoer и не нуждается в переписывании никогда, даже когда написан другой классный объект, о котором библиотека никогда не слышала.
Если вы попытаетесь написать классный файл, который не соответствует требуемой структуре, то исполняемый файл, который использует библиотеку, не скомпилируется.
У coolthingdoer есть некоторые статические функции, которые необходимы.
Я, наверное, гонюсь за плохим дизайном, поэтому, пожалуйста, укажите мне на лучший. Мне нужна фабрика?
Может быть, что-то подобное поможет (см. пример ideone.com):
#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);
}
РЕДАКТИРОВАТЬ: Мне кажется, что OP не нуждается в полиморфизме во время выполнения, а скорее полиморфизм во время компиляции без необходимости экземпляра класса (использование static
функции, когда реализация скрыта в производных классах, экземпляр не требуется). Надеюсь, что приведенный ниже код поможет решить эту проблему (пример на 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);
}
РЕДАКТИРОВАНИЕ № 2: Принудительный сбой во время компиляции в случае, если пользователь не придерживается желаемого шаблона, вот небольшая модификация на 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);
}
Это выглядит как правильное место для реализации схема моста. Может быть, это то, чего вы (неосознанно) желаете достичь. Короче говоря, вы указываете интерфейс и его реализации, а затем вызываете do_thing
метод, в свою очередь, вызывает реализацию по указателю на класс реализатора.