Имеется набор классов для работы с файлами, в которых содержатся таблицы данных разного формата.
Подход для них общий. Открывается файл, построчно читается, каждая строчка обрабатывается соответствующим методом fromString и заполненные переменные нужного класса заносятся в список QList <> для дальнейшей работы.
class record
{
...
int fromString(QString str);
int toString(QString &str);
};
class recordList
{
QList <record*> recList;
recordList();
int init(QString fileName);
int save();
...
};
Как то так. Т.е. у таких классов есть явно общие черты, но и от типа record будут, например, особенности в init(). Подскажите, что тут логичнее применить.
Здравствуйте, NordWest, Вы писали:
NW>Имеется набор классов для работы с файлами, в которых содержатся таблицы данных разного формата. NW>Подход для них общий. Открывается файл, построчно читается, каждая строчка обрабатывается соответствующим методом fromString и заполненные переменные нужного класса заносятся в список QList <> для дальнейшей работы.
NW>
NW>Как то так. Т.е. у таких классов есть явно общие черты, но и от типа record будут, например, особенности в init(). Подскажите, что тут логичнее применить.
А почему нельзя и то и другое? То есть общий класс, но некоторые методы сделать шаблонными.
ZS>А почему нельзя и то и другое? То есть общий класс, но некоторые методы сделать шаблонными.
Просто наследование я ещё как-то понимаю. Расширяю функциональность, перегружаю методы по необходимости. Но тут получается 2 класса. Один как переменная второго. Но в реальности будут использоваться потомки обоих. Тут либо нужно делать класс, считывающий строки, не наследуемым, но с указанием шаблона второго с пустыми определениями fromString,toString, которые перезагрузятся в потомках. Либо как? С наследованием я сталкивался, а вот шаблоны не применял, так что сложно перенести ситуацию в описаниях на данный конкретный пример.
NW>Просто наследование я ещё как-то понимаю. Расширяю функциональность, перегружаю методы по необходимости. Но тут получается 2 класса. Один как переменная второго. Но в реальности будут использоваться потомки обоих. Тут либо нужно делать класс, считывающий строки, не наследуемым, но с указанием шаблона второго с пустыми определениями fromString,toString, которые перезагрузятся в потомках. Либо как? С наследованием я сталкивался, а вот шаблоны не применял, так что сложно перенести ситуацию в описаниях на данный конкретный пример.
Если архитектура подразумевает жесткое, заранее известное связывание потомков recordList с потомками record, то можно попробовать Bridge pattern. Определить интерфейсы в абстрактных классах, а в конкретном потомке recordList делать инстанс конкретного потомка record.
Если предполагается, что любые потомки recordList будут работать с любыми потомками record, то можно попробовать сделать recordList шаблонным, различие работы функции init вынести в отдельную шаблонную функцию и специализировать её для разных типов record. Если нужно одинаковое поведение этой функции для, например, всех потомков какого-то производного типа от record, то смотреть в сторону enable_if и type traits.
Здравствуйте, Valen, Вы писали:
V>Если архитектура подразумевает жесткое, заранее известное связывание потомков recordList с потомками record, то можно попробовать Bridge pattern. Определить интерфейсы в абстрактных классах, а в конкретном потомке recordList делать инстанс конкретного потомка record.
Видимо ближе этот вариант. Т.е. у меня пары классов, наследующие от потомков базовый механизм. Но тут без template не обойтись, так как потомку recordList нужно указать потомка record.
Я сейчас сделал так, в других именах правда:
class tRecord
{
public:
tRecord(){};
int fromString(QString tStr){};
int toString(QString &tStr){};
};
template <class tRecord>
class listFile
{
QList <tRecord*> recList;
QString fileName;
public:
listFile();
int init(QString fname);
int s2rec(QString tStr);
};
listFile::listFile()
{
}
int listFile::init(QString fname)
{
...
return 0;
}
Потом определяю потомков:
class tlRecord : public tRecord
{
public:
double exp;
int Ntot;
QString nam;
...
tlRecord();
int fromString(QString tStr);
void toString(QString &tStr);
tlRecord& operator=(const tlRecord &rhs);
};
class taskList : public listFile <tlRecord>
{
};
Но при определении в программе раздается ругань на все лады. Что не так?
Здравствуйте, Valen, Вы писали:
V>Здравствуйте, NordWest, Вы писали:
NW>>Но при определении в программе раздается ругань на все лады. Что не так? V>Какая именно ругань?
Например:
ошибка: ‘template<class tRecord> class listFile’ used without template parameters
Здравствуйте, NordWest, Вы писали:
NW>Здравствуйте, Valen, Вы писали:
V>>Здравствуйте, NordWest, Вы писали:
NW>>>Но при определении в программе раздается ругань на все лады. Что не так? V>>Какая именно ругань?
NW>Т.е. у меня конструктор не зависит от типа, как его не указывать? Там в объявлении что-то по другому указывается?
Здравствуйте, Valen, Вы писали:
V>Здравствуйте, NordWest, Вы писали:
NW>>Здравствуйте, Valen, Вы писали:
V>>>Здравствуйте, NordWest, Вы писали:
NW>>>>Но при определении в программе раздается ругань на все лады. Что не так? V>>>Какая именно ругань?
NW>>Т.е. у меня конструктор не зависит от типа, как его не указывать? Там в объявлении что-то по другому указывается?
V>Вот пример V>http://ideone.com/dzTDC
А как правильно функции-члены класса определять? Вот я, например, конструктор определяю:
Здравствуйте, Valen, Вы писали:
V>Здравствуйте, NordWest, Вы писали:
NW>>Здравствуйте, Valen, Вы писали:
V>>>Здравствуйте, NordWest, Вы писали:
NW>>>>Но при определении в программе раздается ругань на все лады. Что не так? V>>>Какая именно ругань?
NW>>Т.е. у меня конструктор не зависит от типа, как его не указывать? Там в объявлении что-то по другому указывается?
V>Вот пример V>http://ideone.com/dzTDC
Да, чертовщина какая-то. Пример аналогичен и работает, а тут ничерта(
Ага, сработало. А в темплате-классе вообще можно метод создать? Тот же init. Пока тоже с ошибкой:
prog.cpp: In function ‘int main()’:
prog.cpp:19: error: ‘int List<Record>::init() [with Record = RecordDer]’ is inaccessible
prog.cpp:32: error: within this context
prog.cpp:32: error: ‘List<RecordDer>’ is not an accessible base of ‘ListDer’
Здравствуйте, NordWest, Вы писали:
NW>Здравствуйте, Valen, Вы писали: V>>Не нужно делать конструктор шаблонным. V>>http://ldmitrieva.blogspot.com/2010/11/blog-post_12.html
NW>Ага, сработало. А в темплате-классе вообще можно метод создать? Тот же init. Пока тоже с ошибкой:
Если нужно создать в шаблонном классе шаблонный метод, то это должно выглядеть так:
template<typename T>
class A
{
template<typename U>
int foo(){return 0;}
}
V>template<typename T>
V>class A
V>{
V> template<typename T>
V> int foo(){return 0;}
V>}
V>
V>т.к. метод foo() "уже шаблонный", т.е. зависит от параметра шаблона класса, т.к. разные параметры шаблона создают разные классы.
Извиняюсь, оповещение об ответах не приходят, думал, что заглох вопрос и на другую работу переключился.
Так в том то и дело, что мне нужно определение метода init() в первом классе List. В нем используются функции-члены базового класса Record. Но получается, что для потомка ListDer он не хочет использовать данный метод с подстановкой потомка RecordDer. Только если переопределить init() в классе ListDer всё компилируется. Но теряется смысл. Толи синтаксически как-то неправильно написано, то ли хз.