Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 20.11.2010, 09:59   #1
rommster
Пользователь
 
Регистрация: 05.10.2010
Сообщений: 46
По умолчанию Преобразование типов

Столкнулся с проблемой при изучении книги Лафоре ООП в C++. Имеется пример для перевода из метров в старую английскую систему(футы, дюймы). Сделано это через конструктор с одним параметром - количеством метров, из которых вычисляются эти самые футы.
Код:
#include <iostream>
using namespace std;
///////////////////////////////////////////////////////////
class Distance
{
  private:
	 const float MTF;
    int feet;
	 float inches;
  public:
	 Distance () : feet (0), inches (0.0), MTF (3.280833F)
		{}

	 Distance ( float meters ) : MTF (3.280833F)
		{
			// FloatToDist
		  float fltfeet = MTF * meters;
		  feet = int ( fltfeet );
		  inches = 12 * ( fltfeet - feet );
		}

	 void showdist () const
		{ cout << feet << "\'-" << inches << "\""; }

};
///////////////////////////////////////////////////////////
int main()
{
	Distance mid = 23.1; // нет ошибки

	mid = 14.5;  // ошибка

	mid.showdist();

	cout<<endl;
	system("pause");
	return 0;
}
Почему в указанном месте выдаётся ошибка?
Код:
[C++ Error] E2125 Compiler could not generate operator= for class 'Distance'
Собственно, в книге написано: "так (Distance mid = 23.1) делать можно, а так (mid = 14.5) - нельзя". Не могу понять, почему нельзя?
Вроде бы вся фишка в const float MTF. Если const убрать, то работать будет. Тоже не пойму, почему? Подскажите, пожалуйста.
rommster вне форума Ответить с цитированием
Старый 20.11.2010, 10:03   #2
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,065
По умолчанию

Все очень просто.
Код:
// Это:
Distance mid = 23.1;
// Эквивалентно этому:
Distance mid(23.1);
т.е. в первом случае 23.1 передаётся как параметр конструктору
а вот это:
Код:
mid = 14.5;
уже вызов оператора присваивания, который у класса не перегружен, а соответственно компилятору нечего вызывать, о чем он и сообщает.
pu4koff вне форума Ответить с цитированием
Старый 20.11.2010, 16:14   #3
rommster
Пользователь
 
Регистрация: 05.10.2010
Сообщений: 46
По умолчанию

Хм...ну по логике вещей то так, в ошибке как раз об этом и говорится... Но почему тогда, если const float MTF тупо сделать неконстантным, то всё замечательно работает?
rommster вне форума Ответить с цитированием
Старый 20.11.2010, 17:02   #4
still_alive
Great Code Monkey
Форумчанин
 
Аватар для still_alive
 
Регистрация: 09.08.2007
Сообщений: 533
По умолчанию

Все действительно просто.
mid = 14.5
Что делает компилятор? Он ищет соответствующий оператор присваивания. Не находит. Пытается сделать неявное преобразование типов, для которого этот оператор существует. Делает: из 14.5 вызовом Distance(14.5) создает объект типа Distance (в данном случае компилятору это разрешено, так как конструктор не объявлен как explicit). Слева и справа находятся объекты одного типа. Копирующий оператор присваивания генерируется компилятором и существует всегда. Он тупо копирует данные-члены из одного объекта в другой. При этом будет перезаписано и значение MTF. Если MTF константа, то это недопустимо, поэтому возникает ошибка компиляции.
Я доступно объяснил?)
still_alive вне форума Ответить с цитированием
Старый 21.11.2010, 08:18   #5
rommster
Пользователь
 
Регистрация: 05.10.2010
Сообщений: 46
По умолчанию

Цитата:
Сообщение от still_alive Посмотреть сообщение
Я доступно объяснил?)
Да, спасибо большое) Просто я ожидал в данном случае скорее ошибку типа Cannot modify a const object...
И вообще разве не лучше такую константу объявить как static, а не инициализировать её каждый раз в кострукторах? Не так ли?

В продолжение темы возникла ещё проблема. Допустим есть два класса, во втором определён оператор преобразования. Вот код, классы по сути ничего не содержат, кроме конструкторов и перегруженных операторов с выводом сообщений, просто для демонстрации механизма.
Код:
#include <iostream>
using namespace std;
///////////////////////////////////////////
class firstClass{
public:
	firstClass(){cout<<"\nFirst empty construktor";}
	firstClass(const firstClass & x){cout<<"\nFirst copy construktor";}
	void operator =(const firstClass & x){cout<<"\nFirst operator =";}
};
///////////////////////////////////////////
class secondClass{
public:
	secondClass(){cout<<"\nSecond empty construktor";}
	secondClass(const secondClass & x){cout<<"\nSecond copy construktor";}
	void operator =(const secondClass & x){cout<<"\nSecond operator =";}
	operator firstClass() const{cout<<"\nSecond operator SecondToFirst";}
};
///////////////////////////////////////////
int main()
{
	secondClass s1;    // конструктор без параметров

	cout<<"\n.................\n";
	firstClass f1; 	// конструктор без параметров
	firstClass f2=f1; // конструктор-копировщик

	cout<<"\n.................\n";
	f1=s1;    	// оператор преобразования + оператор присваивания

	cout<<"\n.................\n";
        // проблема здесь:
	firstClass f3=s1; // оператор преобразования + ???

        cout<<"\n.................\n";
	system("pause");
	return 0;
}
Так вот, не могу понять что происходит здесь:
Код:
firstClass f3=s1;
Ну во первых, вызывается оператор преобразования из SecondClass в FirstClass. С этим всё нормально. Потом по идее должен вызваться конструктор, как я подумал копировщик, но почему-то этого не происходит. Каким вообще конструктором создастся этот f3? Спасибо.

Последний раз редактировалось Stilet; 23.11.2010 в 08:58.
rommster вне форума Ответить с цитированием
Старый 22.11.2010, 15:01   #6
still_alive
Great Code Monkey
Форумчанин
 
Аватар для still_alive
 
Регистрация: 09.08.2007
Сообщений: 533
По умолчанию

Цитата:
Сообщение от rommster
Да, спасибо большое) Просто я ожидал в данном случае скорее ошибку типа Cannot modify a const object...
Да нет, тут компилятор абсолютно прав - он не может найти или сгенерировать такой оператор присваивания, при котором указанная строка смогла бы выполниться корректно. О чем и сообщает. А при таком сообщении об ошибке, которое вы ожидали увидеть, поиск причины в большом проекте длился бы в разы дольше.

Цитата:
Сообщение от rommster
И вообще разве не лучше такую константу объявить как static, а не инициализировать её каждый раз в кострукторах? Не так ли?
Так. Эта константа по-видимому общая для всех объектов данного класса и нет смысла не делать ее статической.

Цитата:
Сообщение от rommster
Ну во первых, вызывается оператор преобразования из SecondClass в FirstClass. С этим всё нормально. Потом по идее должен вызваться конструктор, как я подумал копировщик, но почему-то этого не происходит. Каким вообще конструктором создастся этот f3? Спасибо.
Конструктор-копировщик режет слух и глаз, в С++ сообществе он называется конструктор копирования.
A = firstClass для краткости.
Вы правы, но лишь отчасти. Да, по идее сперва должен неявно вызваться оператор преобразования, который сконструированный временный объект типа А передаст в соответствующий конструктор копирования, а после его выполнения этот временный объект будет уничтожен. И семантически ваша программа должна полагаться именно на это (то есть конструктор копирования должен быть доступен).
Но реальность такова, что в целях повышения производительности стандарт позволяет компиляторам избегать создания временных объектов при соблюдении определенных условий: в данном случае соблюдается такое условие, что функция-член operator A() возвращает объект нужного нам типа - типа А. Это позволяет компилятору без создания временного объекта сразу сконструировать нужный объект в нужной области памяти в обход конструктора копирования (даже если этот конструктор что-то делает).
Итак, operator A() не возвращает временный объект типа А, а конструирует объект типа А прямо в области памяти, соответствующей объекту f3.
still_alive вне форума Ответить с цитированием
Старый 23.11.2010, 08:11   #7
rommster
Пользователь
 
Регистрация: 05.10.2010
Сообщений: 46
По умолчанию

Круто) Спасибо за столь подробные объяснения, пойду разбираться дальше.
rommster вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Преобразование типов Ra88 Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 4 22.07.2010 02:56
Преобразование типов Aleksandra1990 Общие вопросы C/C++ 5 12.05.2010 17:32
Си. Преобразование типов pif Помощь студентам 3 20.04.2009 13:54
Преобразование типов DeFace Общие вопросы C/C++ 4 24.03.2009 17:06
Преобразование типов Pronik Общие вопросы Delphi 2 12.06.2007 12:23