#c #static #constructor #constants #static-members
#c #статический #конструктор #константы #статические члены
Вопрос:
Я пытаюсь создать шаблон, который может создавать несколько разных типов классов, которые отличаются в основном названием вещей, т. Е. резистор должен выводить «Сопротивление: 4 Ом», тогда как конденсатор будет выводить «Емкость: 4 фарад» в том же вызове функции, без перегрузки. В идеале единицами измерения должны быть просто статические значения const std::string.
Мой метод состоял в том, чтобы создать базовый класс с неинициализированным
Проблема здесь в том, что теперь мне приходится перегружать все мои различные типы конструкторов во всех подклассах.
Есть ли способ просто инициализировать статические переменные const в подклассе?
Спасибо
Ответ №1:
Инициализация public/protected
членов базового класса внутри конструктора производного класса не разрешена текущим стандартом. Для достижения этого приходится полагаться на другие методы. Есть 2 способа решить вашу проблему.
(1) Объявите virtual
метод, возвращающий std::string
соответствующие метки / значения. Однако это вызовет ненужные накладные расходы. Из вашей реализации я могу понять, что вы хотите избежать этого.
(2) Используйте промежуточный template
класс, который сделает это за вас.
enum eValue { OHM, FARAD, AMP }; // enum to string mapping
static const string sValue[] = { "ohm", "farad", "amp" };
// make the 'value' as reference string; to avoid making multiple copies
class Base {
Base (const string amp;v) : value(v) {}
public: const string amp;value; // has to be accessed using object
};
template<eValue TYPE>
struct Link : Base { // this is an intermediate class for every derived
Link () : Base(sValue[TYPE]) {}
};
class Resistance : public Link<OHM> {
};
Комментарии:
1. Это именно тот ответ, который я искал — может ли конструктор подкласса получить доступ к (унаследованному) общедоступному члену базового класса.. Спасибо!
Ответ №2:
CRTP может быть полезен:
class CircuitElement
{
virtual const std::stringamp; getLabel() const = 0;
virtual const std::stringamp; getUnit() const = 0;
};
template <typename ElementType>
class CircuitElementBase : public CircuitElement
{
public:
const std::stringamp; getLabel() const { return ElementType::Label; }
const std::stringamp; getUnit() const { return ElementType::Unit; }
};
class Resistor : public CircuitElementBase<Resistor>
{
static std::string Label, Unit;
};
std::string Resistor::Label("Resistance: ");
std::string Resistor::Unit("ohm");
Ответ №3:
Зависит от ваших требований, я думаю:
#include <string>
#include <iostream>
#include <sstream>
struct ResistorDescriptor
{
static const std::string type;
static const std::string unit;
};
const std::string ResistorDescriptor::type = "Resistance";
const std::string ResistorDescriptor::unit = "ohm";
struct CapacitorDescriptor
{
static const std::string type;
static const std::string unit;
};
const std::string CapacitorDescriptor::type = "Capacitance";
const std::string CapacitorDescriptor::unit = "farad";
template <class T>
class Element
{
public:
Element(int val) : value(val) {}
std::string output()
{
std::stringstream s;
s << T::type << ": " << value << " " << T::unit << std::endl;
return s.str();
}
private:
int value;
};
int main(int argc, char** argv)
{
Element<ResistorDescriptor> resistor(4);
Element<CapacitorDescriptor> capacitor(5);
std::cout << resistor.output() << capacitor.output() << std::flush;
return 0;
}
вывод:
Resistance: 4 ohm
Capacitance: 5 farad