2016-07-04 1 views
2

У меня есть базовый класс с именами фигур с производным классом трехмерной фигуры, т. Е. Шаром или тэтэдером. Моя программа должна читать тип фигуры и ее параметры из текстового файла и записывать том и область в выходной текст.Построить объект, прочитав его имя из текстового файла

#include <fstream> 
#include <string> 
#include <sstream> 
#include <iostream> 
#include <cstring> 
#include <cstdlib> 
#include "Shape.h" 
#include "Ball.h" 
#include <vector> 

using namespace std; 

int 
main(int argc, char** argv) 
{ 
string input = string(argv[1]); 
string output = string(argv[2]); 

ifstream file(input); 
string line; 

string shapename; 
int nx = atoi(argv[3]); 
int ny = atoi(argv[4]); 
int nz = atoi(argv[5]); 
while (std::getline(file, line)) 
{ 
    std::stringstream lineStream(line); 

    lineStream >> shapename; 
    int value; 
    std::vector<int> lineData; 
    while (lineStream >> value) 
    { 
     lineData.push_back(value); 
    } 

    Shape * objShape = new shapename(lineData); 
    objShape -> calc_volume; 
    objShape -> calc_projection(nx,ny,nz); 

    std::ofstream f(output); 
    f << objShape -> get_volume() << " " << objShape -> get_projection << endl; 
} 


} 

Мой вопрос в том, как я могу создать объект из строки в текстовом файле, особенно без знания всех производных классов.

Должно быть возможно добавить в программу дополнительные формы без изменения кода, только путем добавления новых файлов.

+0

Google завод шаблон. – drescherjm

ответ

2

Возникает вопрос:

Моего вопрос теперь, как я могу создать объект из строки в текстового файла, особенно не зная все производные классы.

Ответ: вы должны знать все производные классы.

C++ does not have reflection. Поскольку такие все имена классов связаны во время компиляции, и этот вид завода не имеет никакого выбора, кроме как сделать некоторые изменения:

if (name == "box") 
    return new Box(); 
else if (name == "circle") 
    return new Circle(); 

// ... etc ... etc ... 

Существуют различные подходы и шаблоны проектирования, которые позволяют автоматизировать некоторые из эта работа работает и делает ее достаточно гибкой, чтобы не было явно поддерживать жесткий список всех подклассов.

Я просто опишу короткий, очень короткий подход. Очень простой, который я использовал раньше, и добивается, в значительной степени, того же результата: фабрика, которая может создавать экземпляр данного подкласса по имени, таким образом, что вам не нужно вручную редактировать завод и добавлять еще несколько строк кода. Весь процесс создания фабрики для нового подкласса может быть аккуратно завершен в процесс создания нового подкласса, что делает его довольно пуленепробиваемым, разделенным решением.

Рассмотрим простой механизм регистрации завод для этих подклассов:

typedef Shape (*shape_factory_t)(); 

Shape ваш суперкласс формы.

Завод будет работать что-то вроде этого:

std::map<std::string, shape_factory_t> all_factories; 

void register_factory(const std::string &name, shape_factory_t factory) 
{ 
    all_factories[name]=factory; 
} 

Так что теперь у вас есть карта всех ваших заводов. Вместо бесконечного if заявления у вас есть одна карта, которую вы можете посмотреть по имени класса, и вызвать соответствующую фабрику, что-то вроде:

auto iter=all_factories.find(name); 

if (iter == all_factories.end()) 
    throw; // Some exception, unknown subclass 

return (*iter->second)(); 

Все права, заботятся, что часть о. Теперь возникает вопрос: как зарегистрировать завод для каждого подкласса.

Допустим, у вас есть реализация Круга:

class Circle : public Shape { 

    class initializer; 

// ... other things that make up the Circle 

}; 

Затем в circle.cpp, который реализует этот подкласс:

static Shape *create_circle() 
{ 
    return new Circle(); // Add constructor parameters, as appropriate 
} 

class Circle::initializer { 

public: 
    initializer() { 
     register_factory("circle", create_circle); 
    } 
}; 

static initializer initialize_me; 

Таким образом, в Circle регистры класса сам с завода, который создает экземпляр заданного Shape по имени класса. Вы можете продолжить и реализовать все остальные подклассы индивидуально, не касаясь основного заводского кода. Вы можете объявить свой подкласс Box таким же образом и зарегистрировать его на заводе, который затем автоматически узнает, чтобы создать класс Box (предположительно, вызывая функцию create_box()), учитывая имя «поле».

Есть еще одна деталь, о которой нужно позаботиться: порядок инициализации. Как вы знаете, относительный порядок инициализации объектов с глобальным охватом в разных единицах перевода является реализованной реализацией и в противном случае не указан C++.

Глобальные std::map всех заводских функций должны быть сконструированы до того, как все подклассы попытаются зарегистрироваться и отправиться на карту при запуске приложения.

Это довольно типичный вопрос static initialization order fiasco, для которого существует несколько известных решений. Здесь объясняется, что in this answer должен работать нормально.

0

C++ не так гибкий. Добавление новых фигур будет означать добавление новых классов (поскольку вы уже создали Shapes, Ball и класс Tetraeder, я предполагаю, что вы хотите создать больше классов). И если вы добавите новые классы, вам придется изменить код, а это значит, что вам нужно перекомпилировать.

У вас есть, чтобы узнать, что такое производные классы. Вы тот, кто их кодирует, поэтому у вас также может быть список из них. Лучшее, что вы можете сделать, чтобы ваша программа была гибкой, - это использование файлов заголовков, которые вы, похоже, все равно делаете.

Что касается создания объекта из строки в текстовом файле (пока вы знаете, что такое классы 3D-объектов), вы можете проанализировать строку, прочитать, какую форму она хочет сделать, а затем сделать что-то довольно простое такие, как это:

//shapeType - a string containing the type of the 3D object 

Shape *newShape; 

switch(shapeType) { 
case "ball": 
    newShape = new Ball(...); // ... - parameters for the ball dimensions 
    break; 
case "tetraeder": 
    newShape = new Tetraeder(...); // ... - parameters again 
    break; 
default: 
    return -1; 
} 

//and now you can use newShape as you wish 
Смежные вопросы