конвертер
но теперь его надо переписать чтобы в нем были следующие вещи:
1)конструирование значения
2)копирование обьекта
3)копирующее присваивание
немного непонятно где можно использовать эти операции.
using namespace std;
enum scaleStatus { MILE, YARD, NM, INCH, FOOT };
struct LengthScale
{
double length;
scaleStatus type;
union
{
double KM;
double MILE;
double YARD;
double NM; //Морские мили (узлы)
double INCH; // Дюймы
double FOOT;
};
};
void toKM(LengthScale* scale)
{
switch (scale->type)
{
case MILE :
{
scale->length = 1.61 * scale->MILE;
break;
}
case YARD :
{
scale->length = 0.0009 * scale->YARD;
break;
}
case NM :
{
scale->length = 1.85 * scale->NM;
break;
}
case INCH :
{
scale->length = 0.00002 * scale->INCH;
break;
}
case FOOT :
{
scale->length = 0.0003 * scale->FOOT;
break;
}
}
}
void fromKM(LengthScale* scale)
{
switch (scale->type)
{
case MILE :
{
scale->length = 0.62 * scale->KM;
break;
}
case YARD :
{
scale->length = 1093.61 * scale->KM;
break;
}
case NM :
{
scale->length = 0.54 * scale->KM;
break;
}
case INCH :
{
scale->length = 39370.08 * scale->KM;
break;
}
case FOOT :
{
scale->length = 3280.84 * scale->KM;
break;
}
}
}
int main()
{
LengthScale l;
l.type = MILE;
l.MILE = 100;
toKM(&l);
cout << l.MILE << "[MILE] is " << l.length << "[KM]" << endl;
l.KM = 85;
fromKM(&l);
cout << l.KM << "[KM] is " << l.length << "[MILE]" << endl;
l.type = YARD;
l.YARD = 1200;
toKM(&l);
cout << l.YARD << "[YARD] is " << l.length << "[KM]" << endl;
l.KM = 22;
fromKM(&l);
cout << l.KM << "[KM] is " << l.length << "[YARD]" << endl;
l.type = NM;
l.NM = 74;
toKM(&l);
cout << l.NM << "[NM] is " << l.length << "[KM]" << endl;
l.KM = 3;
fromKM(&l);
cout << l.KM << "[KM] is " << l.length << "[NM]" << endl;
l.type = INCH;
l.INCH = 250;
toKM(&l);
cout << l.INCH << "[INCH] is " << l.length << "[KM]" << endl;
l.KM = 10;
fromKM(&l);
cout << l.KM << "[KM] is " << l.length << "[INCH]" << endl;
l.type = FOOT;
l.FOOT = 68;
toKM(&l);
cout << l.FOOT << "[FOOT] is " << l.length << "[KM]" << endl;
l.KM = 5;
fromKM(&l);
cout << l.KM << "[KM] is " << l.length << "[FOOT]" << endl;
cin.get();
cin.get();
return 0;
}
...
"Когда вы говорите, Иван Васильевич, ощущение такое, что вы бредите" (c)
Извините :) Но приведенный код, это просто ужас...
1. LengthScale содержит фактически два одинаковых поля численного значения величины.
2. Причем эти величины дают почву для множества ошибок. Например, функция ToKM изменит в переменной поля type и length, а union поле останется тем же, и если переменная будет дальше использоваться - получится что в ней тоже число, что и до конвертации, но единицы измерения уже Км...
1)конструирование значения
Вот оно:
l.type = MILE;
l.MILE = 100;
2)копирование обьекта
Что может быть проще...
m = l;
3)копирующее присваивание
Радуйтесь, присваивание в пункте 2 - копирующее.
Я бы обошелся вообще без объектов. Что-то типа:
{
enum scaleStatus { MILE, YARD, NM, INCH, FOOT, KM};
const double scale[] = { 0.62, 1093.61, 0.54, 39370.08, 3280.84, 1.0};
double Convert(double value, int from, int to)
{
return value * scale[to] / scale[from];
}
};
int main()
{
double km = 1610.0;
double miles = LengthScale::Convert(km, LengthScale::KM, LengthScale::MILE);
cout << miles << endl;
return 0;
}
Но ваш преподаватель наверное хочет, чтобы вы создали иерархию классов, а затем уже перегружали в них конструкторы копирования и т.д. Понятно, что вы озадачены, так как никакой иерархии у вас нет.
Должно быть что-то типа:
// должно быть нужное кол-во наследников
// (по одному на каждый вид преобразования)
class Convert
{
protected:
double initVal, convertVal;
public:
double GetInit(){return initVal;}
double GetConvert(){return convertVal;}
Convert(double val){initVal = val;}
virtual void Compute() = 0;
};
struct KM_to_MILE : public Convert
{
KM_to_MILE(double val):Convert(val){}
virtual void Compute()
{
convertVal = initVal / 1.61;
}
};
int main()
{
KM_to_MILE km(1610.0);
cout << km.GetInit() << " km => ";
km.Compute();
cout << km.GetConvert() << " mile" << endl;
return 0;
}
Должно быть что-то типа:
...
Парень окончательно запутается :(
В задании вроде ничего не говорится про наследование, нужно просто написать класс и перегрузить в нем оператор присваивания.
Дело в том, что пример который дал преподаватель мягко говоря странный...
В задании вроде ничего не говорится про наследование...
Где задание-то? Четкого задания вроде бы и не было.
Чтоб не путаться - я привел простейший пример без классов (можно было бы и без пространства имен для простоты, но я не люблю "свободные" енумы). Недостаток того примера в том, что компилятор не знает из какого типа величины в какой переводить. Т. е. он спокойно переварит следующее:
double yard = LengthScale::Convert(miles, LengthScale::KM, LengthScale::MILE);
но смысл уже будет неверный. Для того, чтобы это устранить и нужны классы. При этом можно либо использовать иерархию классов, а в функции давать указатель на абстрактный класс-предок, либо использовать некрасивые манипуляции, типа определения типа объекта по какому-то его данному.
Ну второй пример я дал для понятия, что такое наследование. Возможно, он не очень применим для работы...
Короче что-то типа того:
{
double val;
public:
virtual double GetScale() = 0;
virtual double GetValue(){return val;}
virtual void SetValue(double v){val = v;}
virtual void Convert(LengthType *p)
{
double res = p->GetValue() * this->GetScale() / p->GetScale();
this->SetValue(res);
}
LengthType(double v):val(v){}
};
class KM : public LengthType
{
static const double scale = 1.0;
public:
virtual double GetScale(){return scale;}
KM(double v):LengthType(v){}
};
class Mile : public LengthType
{
static const double scale = 0.62;
public:
virtual double GetScale(){return scale;}
Mile(double v):LengthType(v){}
};
int main()
{
KM km = 161.11;
Mile mile = 0.0;
mile.Convert(&km);
cout << mile.GetValue() << " miles" << endl;
km.SetValue(0.0);
km.Convert(&mile);
//km.Convert(&km); // теперь нет ошибки, хотя еще нет смысла
cout << km.GetValue() << " km" << endl;
return 0;
}
Переехали кстати не все посты, вот начало.
Задача проще решается структуркой double + enum (код тута)... В вашем варианте легко запутаться, особенно учитывая, что при конвертации нужны отдельные указатели для каждой СИ. На мой взгляд использовать наследование здесь необоснованно.
Нет. Проще использовать enum + массив соответствующих коэффициентов. Тогда никакой switch - case не нужен. Будет короче, и внести новую СИ проще.
Далее. Если вы внимательно посмотрите мой пример с массивом, то заметите, что у меня перевод выполняется из любой единицы в любую, у вас же только в градусы цельсия.
Суть вот в чем: величина в исходной СИ переводится в километры, затем километры переводятся в величину трубуемой на выходе СИ (вместо километров можно использовать другуюпромежуточную СИ).
В последнем моем примере запутаться трудно - он довольно короткий, и сравнительно легко читаемый. Плюс тут как раз в том, что пользователь получает результат, соответствующий типу переменной. Еще плюс в том, что не нужно знать никаких констант, енумов для использования преобразования. И при чем тут указатели? Для каждой СИ у меня нужен отдельный класс-наследник, а не указатель.
... И при чем тут указатели? Для каждой СИ у меня нужен отдельный класс-наследник, а не указатель.
При том, что есть у нас например величина в 25 километров... Объявлена вот так: KM km = 25;
Во первых, чтобы перевести в мили нужно завести ещё одну переменную класса Mile ... или указатель на Mile.
Во-вторых, функция Convert базового класса изменит значение val (использование промежуточной СИ - километров, очень хорошее решение, я не подумал про это) ... но вот сама переменная останется того, же класса KM... От того, что сработал метод базового класса тип переменной не изменится. Получается мы играем на том, что компилятор будет обращаться с этой переменной, как с переменной другого типа... Я думаю это сработает за счет виртуальных функций и статических полей, но все это представляется мне ненадежным...
Я не критикую, сам пытаюсь разобраться :)
Во первых, чтобы перевести в мили нужно завести ещё одну переменную класса Mile ... или указатель на Mile.
Величина km хранит длину только в километрах. Она не дожна хранить ее в милях. Т.е. пользователь всегда будет уверен, что в данной переменной используется определенная СИ.
Соответственно, чтобы перевести ее в мили, нам требуется переменная, которая хранит длину в милях. При этом значение (val) самой переменной km при конвертации не меняется. Меняется только значение переменной типа MILE.
В функции Convert значение исходной переменной передается по указателю. Это обычный прием - ссылаться на переменную базового типа, чтобы пользователь мог подставить указатель на любой класс-потомок. В общем, как я понимаю, это пример полиморфизма: Convert использует виртуальный метод GetScale(), который для каждого потомка возвращает разный коэффициент.
Изменяется не величина из которой переводят, а в которую переводят. То есть, если я пишу
KM km = 161.11;
mile.Convert(&km);
то km останется преждним, в mile запишется значение 100 (100 милей равно 161.11 км - вроде логично).
В любом случае, в этом подходе есть и плюсы и минусы. Но я привел 2 примера - в стиле C и в стиле C++. Выбор есть.
P.S. похоже нам эта тема интереснее, чем топик-стартеру :)
Я сюда хожу не для того, чтобы студентам во время сессии помогать, а чтобы самому учиться и с умными людьми поговорить. Поэтому для меня не важно, кто создал тему - важна сама тема.