Выполняя расчеты для различных переменных


Я использую ниже код, чтобы попробовать и сделать его легко делать здравые расчеты для различных переменных, т. е. давление + высота бессмысленным, и давление в АТМ += давление в барах стоит добавить, принимая единицы во внимание. Я пытался играть вокруг с динамическими и статическими литой, а также ЦРТП по совету других мелких членов биржи общий стек, но не мог получить тех методов работы. Мой код, как это работает, но оператор + возвращает переменную типа Не типа давления.

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

#ifndef PARENT_VARIABLE_H_
#define PARENT_VARIABLE_H_

#include <string>
#include <map>
#include <stdio.h>
#include <typeinfo>
#include <boost/assign.hpp>

template <typename V,typename D> // To let different variables use different S.F.
struct Variable{
    /*
     * This structure is a abstract base class from which all dimensional variables
     * are derived. Derived variables may be operated with and units will be largely
     * automatically handled.
     */

protected:
    //Functions
    Variable(V v, std::string u,std::string * m_type, D conversions [], const std::map<std::string,short> * units);
    //~Variable();
    bool check_type(const std::string & two) const;
    V consistant_units(const Variable & two) const;

    //Variables
    V value;
    std::string unit;
    const std::map<std::string, short> * valid_units; //contains all units for which conversions have been defined.
    D * conversion; //An n by n array for calculating conversions
    std::string * type;

public:
    V get_value() const;
    std::string get_unit() const;
    void change_unit(const std::string & new_unit);

    //Overloaded operators

    //Changes self
    Variable & operator+= (const Variable &t);

    //Returns new Variable type
    Variable & operator+(const Variable & other) const;

};

//////////////////////////////////////////////////////////////////////////////////////////////////////
/*
 * Class functions
 */

FILE * E_FILE;

void warning(const std::string & message){ //Placeholder function I'm not sure what I want to do with my warning messages yet
    E_FILE = fopen ("error_file.txt","w");
    std::cout<<message; // might change to output file
    fclose (E_FILE);
}

template<typename V,typename D>
Variable<V,D>::Variable(V v, std::string u, std::string * m_type, D conversions [], const std::map<std::string,short> * units){
    value = v;
    unit = u;
    conversion = conversions;
    valid_units = units;
    type = m_type;
}

template <typename V,typename D>
V Variable<V,D>::get_value() const{
        return value;
    }

template <typename V,typename D>
std::string Variable<V,D>::get_unit() const{
    return unit;
}

template <typename V,typename D>
void Variable<V,D>::change_unit(const std::string & new_unit){
    if (valid_units->find( new_unit ) == valid_units->end()){//Check the unit is defined
        std::string message = new_unit +" is not a valid unit. /n";
        warning(message);
    }
    else{
        int target = valid_units->find(new_unit)->second;
        int original = valid_units->find(unit)->second;
        value*=conversion[ (original*valid_units->size()) + target];
        unit=new_unit;
    }
}

template <typename V,typename D>
bool Variable<V,D>::check_type(const std::string & two) const{
    if(*type!=two){
        std::string message = two + " is not the same as "
                + *type + " adding them is nonsensical. /n";
        warning(message);
        return false;
    }
    return true;
}

template <typename V,typename D>
V Variable<V,D>::consistant_units(const Variable<V,D> & two) const{
    if (unit!=two.unit){
        std::string message = *type+
                " units different, answer is in "+ unit + " /n";
        warning(message);
        int target = valid_units->find(unit)->second;
        int original = valid_units->find(two.unit)->second;
        return (two.value)*conversion[ (original*valid_units->size()) + target];
    }
    return two.value;
}

template <typename V,typename D>
Variable<V,D> & Variable<V,D>::operator +=(const Variable<V,D> & t){
    if (check_type(*t.type)){
        V other_value = consistant_units(t);
        value += other_value;
    }
    return *this;
}

template <typename V,typename D>
Variable<V,D> & Variable<V,D>::operator+(const Variable<V,D> &other) const {
    return Variable(*this) += other;
  }
/////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////
/*
 * Pressure
 */

template <typename V>
class Pressure : public Variable<V,double> {
public:
    Pressure(V v,std::string u);
    //~Pressure();
};

///////////////////////////////////////////////////////////////////////////////////////////////////////
/*
 * Pressure
 */
static const std::map<std::string, short> PRESSURE_UNITS =
    boost::assign::map_list_of("kPa",0)("atm",1)("psi",2);

static double PRESSURE_CONVERSION[3][3]= {{1,0.009869232667,0.145037738},
                                            {101.325,1,14.6959488},
                                            {6.89475729,0.0680459639,1}};

static std::string PRESSURE_TYPE = "Pressure";

template <typename V>
Pressure<V>::Pressure(V v, std::string u) : Variable<V,double>(v,u,&PRESSURE_TYPE,PRESSURE_CONVERSION[0],&PRESSURE_UNITS){
}

#endif /* PARENT_VARIABLE_H_ */


341
3
c++
задан 29 ноября 2011 в 12:11 Источник Поделиться
Комментарии
1 ответ

Первый взгляд на переменную базового класса:

Я предполагаю, что это всегда должно существовать!
Таким образом, вы должны сделать его ссылкой (Если есть какой-то способ изменить это динамично. Учитывая нынешний интерфейс я не могу видеть способ, чтобы изменить его).

const std::map<std::string, short> * valid_units; //contains all units for which conversions have been defined.

Зачем тебе указатель на строку?

std::string * type;

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

Понятия не имею, как это работает и как вы настраиваете его.
Поэтому, очевидно, нам не хватает много комментариев.

D * conversion; //An n by n array for calculating conversions

Комментарии к конструктор!

Variable(V v, std::string u,std::string * m_type, D conversions [], const std::map<std::string,short> * units);


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

  • еще раз пройти по константной ссылке.

  • m_type: почему вы передавая указатель (даже если вы храните указатель внутренне вы хотите пройти по ссылке (таким образом он не может быть null)).

  • D здесь D представляет собой единый массив измерений. Но выше вы говорите, это Н*массив Н. Это непоследовательно.

  • блоки снова пройти по ссылке (даже если вы храните указатель внутренне).

Desstructor

//~Variable();

Закомментированы? Если это базовый класс, вы лучше иметь хороший повод не делать этот виртуальный. И если есть хорошая причина, она должна быть хорошо документированы здесь.

Проверки типа! Почему бы вы передать строку, чтобы проверить тип?

bool check_type(const std::string & two) const;

Единственной операцией, которую можно выполнить, чтобы проверить, если две переменные имеют тот же тип или нет. Таким образом, эта функция должна принимать ссылку на другую переменную объекта, и вы можете вернуть true/false, если их типы одинаковы/различны.

Понятия не имею, что это должен делать. Требуется дополнительная документация.

V consistant_units(const Variable & two) const;

ОК. Это очевидно.

V value;

Не так очевидно, что это делает:

std::string unit;

ОК. Личные опинио: я ненавижу геттеры/сеттеры. Лучший способ разорвать ваши объекты инкапсулирования когда-либо изобретенных. Также она тесно соединяет ваш класс всегда предоставляя этот интерфейс в будущем, как кто-то будет использовать его, а затем вы будете иметь, чтобы сохранить его.

V get_value() const;

ОК. Я вижу, почему вы хотите получить значение. Но возвращение по ссылке. Также нужно предоставить константная версия, которая возвращает const ссылка на значение. Если вы хотите использовать значение, как части конструктора в этом случае необходимо реализовать конструктор копирования.

std::string get_unit() const;

Нет причин, чтобы быть в состоянии получить единицы!. Вам это нужно, потому что вы реализовали check_type(). Но вы не подтекает ваши абстракции здесь. Предпочитаете изменить check_type(). Другая причина утечки это для потокового целей, но лучшим решением было бы реализовать метод печати.

ОК. Модификации самостоятельно.

Variable & operator+= (const Variable &t);

Но что вы возвращаетесь сюда?

Variable & operator+(const Variable & other) const;

Редактировать: (на основе расширенного вопрос)


Я не уверен, что вы подразумеваете под "Я предполагаю, что это всегда должно существовать! Таким образом, вы должны сделать его ссылкой".

Будет ли когда-нибудь быть null? Если это не null затем пройти по ссылке.


Почему указатель на строку, я хочу, чтобы одну строку, "давление", для всех экземпляров давление, затем другую, "длина" для всех типов длины.

Создать свой набор типов где-то. И передавать ссылки на эти типы переменной.


Мой первый экземпляр был использовать static внутри класса, но как я понимаю это вызовет как давление и длину, чтобы иметь ту же строку, типа.

Вы могли бы иметь статический класс:

struct Variable
{
/* STUFF */
static std::string const PresureType;
static std::string const LengthType;
};

Теперь в конструкторе объекта вы передаете одно из этих значений (по ссылке).

Variable pressure(15, "Bar", PresureType, myConversions, myUnits);


Если бы я был использовать ссылку Не я должен назначить его на торможении. Я что-то упускаю?

Не уверен, что вы имеете в виду. Вы уже проезжаете его cosntructor. Нет никаких изменений.


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

Да избавиться от него. Методы-это действия, которые можно выполнить на ваш объект (любой метод, который не выглядит как глагол является, вероятно, не входят в класс).


Я думал, что речь идет о скопированный экземпляр лхс, который был += к РГО. Я также был под впечатлением, используя по умолчанию конструктор копирования, потому что нужно быть уникальным только величина и единица измерения. Разве это неправильно?

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

3
ответ дан 29 ноября 2011 в 10:11 Источник Поделиться