Я работаю над созданием динамической формы на C++, которая должна вводить N записей пользователя. Число N зависит от типа приложения, выбранного пользователем - при условии, что все поля имеют один и тот же тип. Клиент унаследует этот интерфейс.
Следовательно, я пытаюсь создать интерфейс (используя шаблоны или любые другие методы), но не могу создать такой интерфейс.
Возможно ли то же самое - если да, приведите пример?
Пример псевдокода для формы из 10 полей:
template<int i>
class Field {
public:
Field () {
for (int index = 0 ; index < i ; index ++)
}
};
template<>
class Field<1> {
public:
Field(char * name , int value);
};
class Form : public Field<10>
{
virtual Field1 (char * name , int value) =0;
..........................................
virtual Field10 (char * name , int value) =0;
// so based upon the value of N provided this class should have N pure virtual methods
}
извините, но мне непонятно, чего вы хотите; вы можете написать пример псевдокода?
Добавлен пример псевдокода для пояснения
Как насчет virtual Field(int field_index, char * name , int value) =0;?
Я считаю, что он создаст только один метод интерфейса - так как мы можем заставить пользователя ввести такое количество записей?
Проверить количество созданных записей ...
Тогда проблема, которую я чувствую, заключается в том, что нет методов для ввода N записей?
Ничего не мешает ввести N записей ...
Но это интерфейс, для которого будет создан класс реализации - следовательно, когда объект класса создается, пользователю необходимо переопределить методы, которые являются фактической логикой для реализации.





Есть много разных способов сделать это.
Вы сказали, что хотите, чтобы все поля были одного типа.
Вот простое решение с вектором.
Если вам нравится, вы также можете легко изменить мой пример, чтобы использовать карту, если вы хотите получить доступ к полям по имени, а не по индексу.
/*********************
* File: main.cpp *
*********************/
#include <iostream>
#include "Form.h"
using std::cout;
using std::endl;
int main(int argc, char* argv[])
{
Form<int> form(15);
// The first field is the customer number
form.setFieldName(0, "customer number");
form.setFieldValue(0, 4711);
// The second field is the order number
form.setFieldName(1, "order number");
form.setFieldValue(1, 1234);
// The third field is an article number
form.setFieldName(2, "article number");
form.setFieldValue(2, 6789);
// ... and so on ...
// Read some values back
cout << "This is the second field:" << endl;
cout << "Field Name: [" << form.getFieldName(1) << "]" << endl;
cout << "Field Value: [" << form.getFieldValue(1) << "]" << endl;
return 0;
}
А вот шаблон, включенный в Main.cpp:
/*****************
* File: Form.h *
*****************/
#pragma once
#include "FormField.h"
template<class T>
class Form
{
public:
explicit Form(const int size);
virtual ~Form() = default;
void setFieldName(int index, const std::string& name);
const std::string& getFieldName(int index) const;
void setFieldValue(int index, const T& value);
const T& getFieldValue(int index) const;
private:
std::vector<FormField<T>> formFields;
};
template<class T>
Form<T>::Form(const int size)
: formFields(size)
{ }
template<class T>
void Form<T>::setFieldName(int index, const std::string& name)
{
formFields[index].setName(name);
}
template<class T>
const std::string& Form<T>::getFieldName(int index) const
{
return formFields[index].getName();
}
template<class T>
void Form<T>::setFieldValue(int index, const T& value)
{
formFields[index].setValue(value);
}
template<class T>
const T& Form<T>::getFieldValue(int index) const
{
return formFields[index].getValue();
}
А это шаблон для FormField:
/**********************
* File: FormField.h *
**********************/
#pragma once
#include <string>
#include <vector>
template<class T>
class FormField
{
public:
explicit FormField();
virtual ~FormField() = default;
const std::string& getName() const;
void setName(const std::string& name);
const T& getValue() const;
void setValue(const T& value);
private:
std::string name;
T value;
};
template<class T>
FormField<T>::FormField()
: name(), value()
{
}
template<class T>
const std::string& FormField<T>::getName() const
{
return name;
}
template<class T>
const T& FormField<T>::getValue() const
{
return value;
}
template<class T>
void FormField<T>::setName(const std::string& name)
{
this->name = name;
}
template<class T>
void FormField<T>::setValue(const T& value)
{
this->value = value;
}
Это все.
Спасибо - этого достаточно, но есть ли способ заставить код выдавать ошибку компиляции, пока не будут установлены все поля?
Не уверен, что понимаете, что именно вы хотите, но ... Я полагаю, вы можете использовать рекурсию и тип тега (скажем, std::integral_constant<std::size_t, N>, где N - это аргумент шаблона для Field), чтобы различать геттер и сеттер на разных уровнях.
Я имею в виду ... учитывая следующий Field
template <typename T, std::size_t N>
class Field : public Field<T, N-1u>
{
private:
std::string name;
T value;
public:
using Field<T, N-1u>::setField;
using Field<T, N-1u>::getFieldName;
using Field<T, N-1u>::getFieldValue;
using icnc = std::integral_constant<std::size_t, N> const;
virtual void setField (icnc &, std::string const & n0, T const & v0)
{
name = n0;
value = v0;
}
virtual std::string const & getFieldName (icnc &) const
{ return name; }
virtual T const & getFieldValue (icnc &) const
{ return value; }
};
и наземная специализация Field<0>, которая определяет поддельные методы
template <typename T>
class Field<T, 0u>
{
public:
// fake ground functions
virtual void setField () { };
virtual void getFieldName () { };
virtual void getFieldValue () { };
};
определение Form следующим образом
class Form : public Field<int, 10u>
{ };
у вас есть 10 виртуальных сеттеров и 20 (10 для имен и 10 для значений) виртуальных получателей.
Ниже приведен полный рабочий пример.
#include <string>
#include <iostream>
#include <type_traits>
template <typename T, std::size_t N>
class Field : public Field<T, N-1u>
{
private:
std::string name;
T value;
public:
using Field<T, N-1u>::setField;
using Field<T, N-1u>::getFieldName;
using Field<T, N-1u>::getFieldValue;
using icnc = std::integral_constant<std::size_t, N> const;
virtual void setField (icnc &, std::string const & n0, T const & v0)
{
name = n0;
value = v0;
}
virtual std::string const & getFieldName (icnc &) const
{ return name; }
virtual T const & getFieldValue (icnc &) const
{ return value; }
};
template <typename T>
class Field<T, 0u>
{
public:
// fake ground functions
virtual void setField () { };
virtual void getFieldName () { };
virtual void getFieldValue () { };
};
class Form : public Field<int, 3u>
{
// Form inherit three different setField, three different getFieldName
// and three different getFieldValie methods
};
template <std::size_t N>
using tag = std::integral_constant<std::size_t, N> const;
int main ()
{
Form f;
f.setField(tag<1u>{}, "field 1", 111);
f.setField(tag<2u>{}, "field 2", 222);
f.setField(tag<3u>{}, "field 3", 333);
std::cout << f.getFieldName(tag<1u>{}) << ", "
<< f.getFieldValue(tag<1u>{}) << std::endl;
std::cout << f.getFieldName(tag<2u>{}) << ", "
<< f.getFieldValue(tag<2u>{}) << std::endl;
std::cout << f.getFieldName(tag<3u>{}) << ", "
<< f.getFieldValue(tag<3u>{}) << std::endl;
}
Еще немного поработаем внутри Form, добавив установщик шаблонов и пару геттеров шаблонов.
class Form : public Field<int, 3u>
{
public:
using Field<int, 3u>::setField;
using Field<int, 3u>::getFieldName;
using Field<int, 3u>::getFieldValue;
template <std::size_t N>
using tag = std::integral_constant<std::size_t, N> const;
template <std::size_t N>
void setField (std::string const & n0, int v0)
{ setField(tag<N>{}, n0, v0); }
template <std::size_t N>
std::string const & getFieldName () const
{ return getFieldName(tag<N>{}); }
template <std::size_t N>
int const & getFieldValue () const
{ return getFieldValue(tag<N>{}); }
};
вы можете упростить использование индекса тега
Form f;
f.setField<1u>("field 1", 111);
f.setField<2u>("field 2", 222);
f.setField<3u>("field 3", 333);
std::cout << f.getFieldName<1u>() << ", " << f.getFieldValue<1u>()
<< std::endl;
std::cout << f.getFieldName<2u>() << ", " << f.getFieldValue<2u>()
<< std::endl;
std::cout << f.getFieldName<3u>() << ", " << f.getFieldValue<3u>()
<< std::endl;
Спасибо за пример - этого достаточно, но есть ли способ заставить код выдавать ошибку компиляции, пока не будут установлены все поля?
Я предполагаю ошибку в методе шаблона get-field (см. Последнюю часть моего ответа); Например, вы можете добавить логический флаг в каждую специализацию Field и метод проверки флага в следующем Field (и, рекурсивно, каждый флаг).
звучит так, как будто вам нужен
std::vectorизentries.