У меня есть общий вопрос дизайна. Я пытаюсь реализовать что-то вроде этого:
------------
|Base Class|
------------
|
------------------
| |
----------- -----------
|SubClass1| |SubClass2|
----------- -----------
| |
-------------- --------------
|SubSubClass1| |SubSubClass2|
-------------- --------------
где базовый класс предоставляет виртуальные функции, подклассы — реализацию, а подклассы — предоставляют константы реализациям.
Я подумал об использовании «Любопытно повторяющегося шаблона» дважды, как это:
// header baseclass.h
template <typename subclass>
class baseclass {
private:
public:
virtual double GetQuantity1(double given1, double given2) = 0;
virtual double GetQuantity2(double given1) = 0;
}
// header subclass1.h
template <typename n>
class subclass1:public baseclass<subclass>{
private:
private1(double, double);
public:
double GetQuantity1(double given1, double given2);
double GetQuantity2(double given1);
}
// header subsubclass1.h
class subsubclass1:public subclass1<subsubclass1>{
private:
public:
double constant1;
double constant2;
}
Затем я бы вызвал Subsubclass :: GetQuantity1 () при использовании кода.
Это что-то вроде кошерной вещи или есть лучшие способы сделать что-то подобное?
Заранее большое спасибо.
Это нормально, и я не вижу никакого общего недостатка в этом. Я просто не понимаю, где вы на самом деле используете CRTP и почему простое виртуальное наследование не будет работать в вашем случае использования (CRTP обычно используется как статический полиморфизм).
Также не понимаю, что вы имеете в виду
private1(double, double);
в вашем subclass1
Вы имели в виду конструктор? В нынешнем виде он не будет компилироваться при создании экземпляра (функции не допускаются без возвращаемого значения, кроме конструкторов или деструкторов).
Другой критик будет: если вы имеете в виду константы, вы должны объявить const
или же static const
члены в ваших подклассах.
Поскольку вы не можете четко указать конкретный вариант использования, трудно сказать, что действительно будет лучшим дизайном для него. Я могу просто предоставить альтернативу, уловленную попыткой следовать вашим мыслям:
// header baseclass.h
template <typename subclass>
class baseclass {
public:
inline double GetQuantity1(double given1, double given2) {
// may be add a static check for GetQuantity1_Impl with a traits
// check on subclass.
return static_cast<subclass*>(this)->GetQuantity1_Impl(given1,given2);
}
inline double GetQuantity2(double given1) {
return static_cast<subclass*>(this)->GetQuantity2_Impl(given1);
}
// You also can provide default implementations, otherwise the interface
// method will be required from subclass to compile correctly
inline double GetQuantity1_Impl(double given1, double given2) {
// ...
}
};
// header subclass1.h
template<double const1, double const2>
class subclass1:public baseclass<subclass1>{
public:
subclass1() {}
double GetQuantity1_Impl(double given1, double given2) {
return 0.0; // Apply formula using the constants instead of 0.0
}
double GetQuantity2_Impl(double given1) {
return 0.0; // Apply formula using the constants instead of 0.0
}
};
// Client implementation file
// No need for subsubclass1 just instantiate for usage
subclass1<0.3, 3.1415> myAlgo;
// A client calls the public interface of the (implicit) base class
double result1 = myAlgo.GetQuantity1(23.2,42);
double result2 = myAlgo.GetQuantity2(2.71828);
Исключите определения чисто виртуальных методов в базовом классе и замените их статической проверкой интерфейса («черты») на subclass
параметр шаблона.
Других решений пока нет …