operators (Помогите разобраться)
Модератор: Модераторы разделов
-
kkkggg
- Сообщения: 100
operators
class complex
{
double re,im;
public:
complex (double r, double i):re®,in(i) {} // (**)
complex operator+ (complex);
complex operator* (complex);
};
int main ()
{
complex a = complex(1,3,1);
complex b = complex(1.2,2);
complex c = b;
a = b+c;
b = b+c*a;
c = a*b+complex(1,2);
return 0;
}
Почему не работает, пример выдрал их "Бьерн Страуструп специальное издание" страница 310
c++ пишет: undefined reference to `complex::operator+(complex)'
Обратите внимание на строку с коментарием **, что значит :re®,in(i) ?
{
double re,im;
public:
complex (double r, double i):re®,in(i) {} // (**)
complex operator+ (complex);
complex operator* (complex);
};
int main ()
{
complex a = complex(1,3,1);
complex b = complex(1.2,2);
complex c = b;
a = b+c;
b = b+c*a;
c = a*b+complex(1,2);
return 0;
}
Почему не работает, пример выдрал их "Бьерн Страуструп специальное издание" страница 310
c++ пишет: undefined reference to `complex::operator+(complex)'
Обратите внимание на строку с коментарием **, что значит :re®,in(i) ?
-
Michael
- Сообщения: 92
Re: operators
Нет определения функции complex::operator+
re®,im(i) - значит, что re присваивается знаение r, а im - значение i.
-
Zeus
- Сообщения: 694
Re: operators
Так а где реализации операторов-то? Объявления есть, а реализации?
И ещё как говорится "замеченные опечатки":
- в этой же строке (**) должно быть не in(i), а im(i)
- где создаётся объект a конструктору передаётся почему-то 3 параметра.
Видимо подразумевается, что вместо одной из запятых должна быть точка?
И ещё как говорится "замеченные опечатки":
- в этой же строке (**) должно быть не in(i), а im(i)
- где создаётся объект a конструктору передаётся почему-то 3 параметра.
Видимо подразумевается, что вместо одной из запятых должна быть точка?
-
kkkggg
- Сообщения: 100
Re: operators
[quote name='Zeus' post='211954' date='Jun 4 2006, в 12:28']
Так а где реализации операторов-то? Объявления есть, а реализации?
И ещё как говорится "замеченные опечатки":
- в этой же строке (**) должно быть не in(i), а im(i)
- где создаётся объект a конструктору передаётся почему-то 3 параметра.
Видимо подразумевается, что вместо одной из запятых должна быть точка?
[quote]
Это всё опечатки и все мои, на быструю руку набивал
[quote]
re®,im(i) - значит, что re присваивается знаение r, а im - значение i.
[quote]
А чем плохо "re = r, im = i"?
Так а где реализации операторов-то? Объявления есть, а реализации?
И ещё как говорится "замеченные опечатки":
- в этой же строке (**) должно быть не in(i), а im(i)
- где создаётся объект a конструктору передаётся почему-то 3 параметра.
Видимо подразумевается, что вместо одной из запятых должна быть точка?
[quote]
Это всё опечатки и все мои, на быструю руку набивал
[quote]
re®,im(i) - значит, что re присваивается знаение r, а im - значение i.
[quote]
А чем плохо "re = r, im = i"?
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
В данном случае это ничем не хуже, но вообще говоря вместо double может быть ваш собственный тип с конструктором, которому нужны параметры, и такой синтаксис - единственный вариант создать объект, используя конструктор не по умолчанию. А в этом случае просто для унификации кода.
-
Zeus
- Сообщения: 694
Re: operators
На сколько я понимаю, если делать так как в примере, то при конструировании этих double'ов используется копирующий конструктор.
А так как ты написал - сначала отработает конструктор по-умолчанию, а потом вызовется оператор присваивания.
Дольше, короче.
PS: И реализацию-то всё-таки не забудь добавить
А так как ты написал - сначала отработает конструктор по-умолчанию, а потом вызовется оператор присваивания.
Дольше, короче.
PS: И реализацию-то всё-таки не забудь добавить
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Для простых типов вроде int и double конструктор по умолчанию не вызывается, т.е. по умолчанию в них мусор после инициализации. Поэтому не дольше.
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Что такое автоматические переменные?
Я имею ввиду, что если есть код типа
Код: Выделить всё
struct A { int a; };
struct B { int a; B() : a() {} };
int main( )
{
A a;
B b;
std::cout << a.a << " " << b.a << std::endl;
}то первым числом выведется мусор, а вторым 0.
-
Zeus
- Сообщения: 694
Re: operators
Автоматическая переменная это как-раз это a и b.
Раньше насколько помню для таких переменных встроенных типов компилятор обеспечивал начальное значение 0.
Раньше насколько помню для таких переменных встроенных типов компилятор обеспечивал начальное значение 0.
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Ну может быть..
Сейчас посмотрел в стандарт, вот что говорят:
(standard) писал(а):12.6.2.4
If a given nonstatic data member or base class is not named by a mem-initializer-id (including the case
where there is no mem-initializer-list because the constructor has no ctor-initializer), then
— If the entity is a nonstatic data member of (possibly cv-qualified) class type (or array thereof) or a base
class, and the entity class is a non-POD class, the entity is default-initialized (8.5). If the entity is a non-
static data member of a const-qualified type, the entity class shall have a user-declared default construc-
tor.
— Otherwise, the entity is not initialized. If the entity is of const-qualified type or reference type, or of a
(possibly cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of
a const-qualified type, the program is ill-formed.
Да и компилятор с ним согласен.
-
kkkggg
- Сообщения: 100
Re: operators
Бог ты мой, вопрос на 2,5 бала, а в какие дебри забрели....
Ладно помогите пожалуйста определить вункцию complex::operator+, для данного примера. Первый раз связался с "operator", и пока не доходит...
Ладно помогите пожалуйста определить вункцию complex::operator+, для данного примера. Первый раз связался с "operator", и пока не доходит...
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Код: Выделить всё
complex complex::operator+ (complex c)
{
return complex(re + c.re, im + re.im);
}-
oav
- Бывший модератор
- Сообщения: 296
Re: operators
v04bvs писал(а): ↑06.06.2006 09:39Код: Выделить всё
complex complex::operator+ (complex c) { return complex(re + c.re, im + re.im); }
Господа адепты С++, ну-ка напишите насколько _плох_ такой "пример". УжОс просто
зы. для интереса добавьте в коструктор complex вывод какой-нить строчки и в конструктор копирования тоже и посмотрите вывод на консоль
-
Zeus
- Сообщения: 694
Re: operators
Мне вообще приличный код operator+ видится с трудом.
Вроде лучше ссылку передать, а передавать ссылку на автоматическую переменную нельзя.
Тогда придётся динамически память выделять? А освобождать где? И неочевидно это для использующего этот оператор...
Лучше operator+= перегрузить
Вроде лучше ссылку передать, а передавать ссылку на автоматическую переменную нельзя.
Тогда придётся динамически память выделять? А освобождать где? И неочевидно это для использующего этот оператор...
Лучше operator+= перегрузить
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Ну что было в первом посте, то я и написал. Конечно надо сделать конструктор преобразования, оператор определить отдельно от класса, использовать константные ссылки, но для автора вопроса, на мой взгляд, это будет несколько сложновато.
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Zeus писал(а): ↑06.06.2006 11:38Мне вообще приличный код operator+ видится с трудом.
Вроде лучше ссылку передать, а передавать ссылку на автоматическую переменную нельзя.
Тогда придётся динамически память выделять? А освобождать где? И неочевидно это для использующего этот оператор...
Лучше operator+= перегрузить
А чем плох вариант
Код: Выделить всё
inline complex operator+( const complex &c1, const complex &c2 )
{
return complex(c1.re() + c2.re(), c1.im() + c2.im());
}Причём, насколько я помню, если писать
complex c = a + b
то даже лишнего вызова конструктора копирования может не быть.
Код: Выделить всё
complex::complex( const float a_re ) :
re_(a_re), im_(0)
{
}и потом писать
complex c = 2;
Чтобы можно было писать такие штуки
complex a, b, c;
...
c = a + b;
a = c + 3;
b = 4 + a;
c = 2 + 3;
т.к. полностью интегрировать комплексное число и вещественное.
-
sdk
- Бывший модератор
- Сообщения: 210
Re: operators
А еще лучше так:
Потому что, если без const, то можно делать такие вот непонятные штуки:
a+b = c
Код: Выделить всё
inline const complex operator+( const complex &c1, const complex &c2 )Потому что, если без const, то можно делать такие вот непонятные штуки:
a+b = c
Серьезность - это способ сделать простые вещи сложными.
Если много знать - устанут глаза. Если много спать - то нет.
Нас никому не сбить с пути - нам пофигу куда идти.
:-)
Если много знать - устанут глаза. Если много спать - то нет.
Нас никому не сбить с пути - нам пофигу куда идти.
:-)
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Действительно :-)
Даже не думал про это.
Даже не думал про это.
-
Zeus
- Сообщения: 694
Re: operators
v04bvs писал(а): ↑06.06.2006 11:45А чем плох вариант
Код: Выделить всё
inline complex operator+( const complex &c1, const complex &c2 ) { return complex(c1.re() + c2.re(), c1.im() + c2.im()); }
Я как-то с inline'ами особо не работал.
Как такой код будет работать?
Какова будет область видимости конструируемого complex'а?
Что сделает оператор return?
Причём, насколько я помню, если писать
complex c = a + b
то даже лишнего вызова конструктора копирования может не быть.
А где тут конструктор копирования?
А-а, надо ж. Я и не знал что оно так называется.
и потом писать
complex c = 2;
Чтобы можно было писать такие штуки
complex a, b, c;
...
c = a + b;
a = c + 3;
b = 4 + a;
c = 2 + 3;
т.к. полностью интегрировать комплексное число и вещественное.
А конструктор тут причём? Я думал тут операторы работают.
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Я как-то с inline'ами особо не работал.
Как такой код будет работать?
Какова будет область видимости конструируемого complex'а?
Что сделает оператор return?
Что то я ничего не понял.. inline это подсказка компилятору, что код функции маленький, и его желательно бы не выделять в отдельную функцию, а подставить в код. Что то вроде макроса. Хотя это только пожелание компилятору, он чего хочет, то и делает.
Будет работать обычно. Если вас смущает inline, можете его убрать, внешне ничего не изменится.
оператор return возвратит объект, сконструированный с помощью соотв. конструктора.
Можно так написать
Код: Выделить всё
complex temp(c1.re() + ..., ...);
return temp;просто тот код короче.
А где тут конструктор копирования?
Ну компилятор может трактовать
complex c = a + b;
как
complex c(operator+(a, B)); // конструктор копирования
или как
complex c(a.re() + b.re(), a.im() + b.im()); // конструктора копирования нет
А конструктор тут причём? Я думал тут операторы работают.
Ну конечно можно наопределять операторов на каждый чих, вроде
operator+(const complex&, const complex&);
operator+(const complex&, float);
operator+(float, const complex&);
но проще определить только первый, и тогда вызов
c = 2 + a;
будет трактован как
c.operator=(operator+(complex(2), a));
т.е. компилятор достаточно умён, чтобы понять, что 2 можно преобразовать в complex с помощью конструктора преобразования, и потом результат подставить в operator+
-
Zeus
- Сообщения: 694
Re: operators
v04bvs писал(а): ↑06.06.2006 13:20
Я как-то с inline'ами особо не работал.
Как такой код будет работать?
Какова будет область видимости конструируемого complex'а?
Что сделает оператор return?
Что то я ничего не понял.. inline это подсказка компилятору, что код функции маленький, и его желательно бы не выделять в отдельную функцию, а подставить в код.
Это-то я знаю. Получается в машинном коде никакого call-вызова собственно и не будет, тогда что будет делать return? И куда он будет "возвращать" сконструированный объект?
Что то вроде макроса. Хотя это только пожелание компилятору, он чего хочет, то и делает.
Будет работать обычно. Если вас смущает inline, можете его убрать, внешне ничего не изменится.
оператор return возвратит объект, сконструированный с помощью соотв. конструктора.
Ну и чем это тогда лучше первого предложенного тобой варианта?
А где тут конструктор копирования?
Ну компилятор может трактовать
complex c = a + b;
как
complex c(operator+(a, B)); // конструктор копирования
или как
complex c(a.re() + b.re(), a.im() + b.im()); // конструктора копирования нет
...
Ну конечно можно наопределять операторов на каждый чих, вроде
operator+(const complex&, const complex&);
operator+(const complex&, float);
operator+(float, const complex&);
но проще определить только первый, и тогда вызов
c = 2 + a;
будет трактован как
c.operator=(operator+(complex(2), a));
т.е. компилятор достаточно умён, чтобы понять, что 2 можно преобразовать в complex с помощью конструктора преобразования, и потом результат подставить в operator+
Что-то многовато компилятор "может трактовать".
Сейчас времени нет проверить, надо не забыть на досуге.
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Да, никакого call вызова не будет. И ретурна не будет. "Возвращать" он будет туда, куда написано в вызывающем коде.
Ну и чем это тогда лучше первого предложенного тобой варианта?
Тем, что параметр передаётся по ссылке, а не по значению (что помогает избежать, как на это намекал oav, ненужного копирования параметра). Так же есть небольшое отличие между определением оператора сложения как члена класса и как отдельной функции.
На всякий случай повторюсь, первый мой вариант предложен не мною, а автором топика. Я всего лишь написал реализацию.
Что-то многовато компилятор "может трактовать".
Сейчас времени нет проверить, надо не забыть на досуге.
Ну в основном "может трактовать" относится к оптимизации. Т.е. может оптимизировать, может не оптимизировать.
-
Zeus
- Сообщения: 694
Re: operators
Ну тогда он отличается от варианта без inline.
Потому что не будет конструироваться стековый объект который будет возвращаться из функции.
Ну и чем это тогда лучше первого предложенного тобой варианта?
Тем, что параметр передаётся по ссылке, а не по значению
А-а, блин, я и не заметил
Я-то всё смотрю когда появится ВОЗВРАТ не значения, а ссылки. И как он будет реализован
Что-то многовато компилятор "может трактовать".
Сейчас времени нет проверить, надо не забыть на досуге.
Ну в основном "может трактовать" относится к оптимизации. Т.е. может оптимизировать, может не оптимизировать.
По-моему ТАКИЕ вещи уже трудно отнести к оптимизации - слишком они принципиальные.
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
почему не будет. Может и сконструироваться, это ничему не противоречит.
Если написано
Код: Выделить всё
inline Class foo() { return Class(1, 2, 3); }
...
v = foo();то он может сделать что-то вроде
Код: Выделить всё
Class ret_value(1, 2, 3);
v = ret_value;конечно это псевдокод. Но принцип примерно такой. Хотя здесь я лучше не буду ни о чём говорить, т.к. такие вещи для меня - тёмный лес. Единственное, в чём я уверен, проверить, "синлайнил" ли компилятор функцию или нет, можно только анализом ассемблерного кода.
Я-то всё смотрю когда появится ВОЗВРАТ не значения, а ссылки. И как он будет реализован
Ох, я не буду утверждать, что моё мнение - истина в последней инстанции, но я уверен, что возврат ссылки в случае отличном от реализации operator[] - ОЧЕНЬ большое зло. Кстати в книжке "Rules for C and C++ programming это совет 121, в Effective C++ - Item 31. Даже процитирую
Item 31: Never return a reference to a local object or to a dereferenced pointer initialized by new within the function.
This Item may sound complicated, but it's not. It's simple common sense. Really. Honest. Trust me.
По-моему ТАКИЕ вещи уже трудно отнести к оптимизации - слишком они принципиальные.
что конкретно вы имеете в виду? Единственный случай, когда оптимизация влияет на логику программы - return value optimization. (насколько мне известно) И это кстати то, что я имел ввиду, когда писал строчку
Код: Выделить всё
complex c(a.re() + b.re(), a.im() + b.im()); // конструктора копирования нетКак я понимаю, это именно то место и та причина, где вам хотелось бы возвращать ссылку. Не нужно.
-
Zeus
- Сообщения: 694
Re: operators
v04bvs писал(а): ↑06.06.2006 14:29
почему не будет. Может и сконструироваться, это ничему не противоречит.
Если написано
Код: Выделить всё
inline Class foo() { return Class(1, 2, 3); } ... v = foo();
то он может сделать что-то вроде
Код: Выделить всё
Class ret_value(1, 2, 3); v = ret_value;
Объект создастся 1 раз. Он же и присвоится.
А если создать объект в функции и вернуть его значение, то создастся ещё один объект в который скопируется значение автоматической (локальной - для данной функции) переменной и ЭТОТ объект вернётся вызывающему коду.
Я-то всё смотрю когда появится ВОЗВРАТ не значения, а ссылки. И как он будет реализован
Ох, я не буду утверждать, что моё мнение - истина в последней инстанции, но я уверен, что возврат ссылки в случае отличном от реализации operator[] - ОЧЕНЬ большое зло.
Ну зло - не зло, но его и реализовать-то красиво не удастся.
Ссылку на локальную переменную вернуть нельзя (как у тебя уже написано в цитате).
Динамическую переменную - коряво и почти никогда не соответствует семантике оператора. Т.е. тому, что от него ожидает другой программист.
По-моему ТАКИЕ вещи уже трудно отнести к оптимизации - слишком они принципиальные.
что конкретно вы имеете в виду? Единственный случай, когда оптимизация влияет на логику программы - return value optimization. (насколько мне известно)
Я не про влияние на логику говорю, а про "прозрачность" программы.
Чтобы по коду было понятно ЧТО ИМЕННО отработает в данной строке.
Чтобы объекты создавались только тогда, когда это нужно программисту.
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Покажи конкретную программу, где это демонстрируется.
Ну зло - не зло, но его и реализовать-то красиво не удастся.
Ссылку на локальную переменную вернуть нельзя (как у тебя уже написано в цитате).
Динамическую переменную - коряво и почти никогда не соответствует семантике оператора. Т.е. тому, что от него ожидает другой программист.
Можно статическую переменную =) Типа
Код: Выделить всё
complex& operator+(...)
{
static complex result;
result.re = ..;
return result;
}Можно какую-нибудь глобальную перемнную в анонимном namespace-е объявить. Способы то есть..
Я не про влияние на логику говорю, а про "прозрачность" программы.
Чтобы по коду было понятно ЧТО ИМЕННО отработает в данной строке.
Чтобы объекты создавались только тогда, когда это нужно программисту.
Всё равно не понял. Кажется мы про разные вещи говорим. Если объект создаётся тогда, когда это не нужно программисту, будут вызываться конструкторы и деструкторы => меняется логика программы.
-
Zeus
- Сообщения: 694
Re: operators
Конкретно - можно в код конструктора вставить какой-нибудь вывод.
А теоретически это следует вот из чего: область видимости локальной переменной - только функция, где она создана (там и умрёт). А что тогда вернётся "наверх", в вызывающий код?
По этой же причине нельзя возвращать ссылку на локальные (автоматические) переменные: к моменту их использования этих переменных уже нет.
Ну зло - не зло, но его и реализовать-то красиво не удастся.
Ссылку на локальную переменную вернуть нельзя (как у тебя уже написано в цитате).
Динамическую переменную - коряво и почти никогда не соответствует семантике оператора. Т.е. тому, что от него ожидает другой программист.
Можно статическую переменную =)
Можно какую-нибудь глобальную перемнную в анонимном namespace-е объявить. Способы то есть..
И всегда возвращать одну и ту же переменную?
Это как-раз то о чём я говорил: программист не рассчитывает на такое поведение оператора.
А способы наверное есть... Ну хотя бы пул переменных завести и возвращать их по-очереди, а когда кончатся - расширить пул. Прикинь изврат какой!
Я не про влияние на логику говорю, а про "прозрачность" программы.
Чтобы по коду было понятно ЧТО ИМЕННО отработает в данной строке.
Чтобы объекты создавались только тогда, когда это нужно программисту.
Всё равно не понял. Кажется мы про разные вещи говорим. Если объект создаётся тогда, когда это не нужно программисту, будут вызываться конструкторы и деструкторы => меняется логика программы.
Вот и не должно этого получиться в результате оптимизации.
Т.е. не должно быть неоднозначностей вроде описанных выше:
Ну компилятор может трактовать
complex c = a + b;
как
complex c(operator+(a, cool.gif); // конструктор копирования
или как
complex c(a.re() + b.re(), a.im() + b.im()); // конструктора копирования нет
По-моему этот код должен однозначно означать:
1. Создаётся объект c конструктором по-умолчанию.
2. Вызывается operator+ который создаёт промежуточный объект complex
3. Вызывается operator= которому передаётся объект complex (лучше - по-ссылке, а то создастся ещё один объект complex при вызове оператора).
-
v04bvs
- Сообщения: 636
- ОС: Debian GNU/Linux
Re: operators
Я всё же настойчиво прошу пример и то, что он выведет.
Это как-раз то о чём я говорил: программист не рассчитывает на такое поведение оператора.
А способы наверное есть... Ну хотя бы пул переменных завести и возвращать их по-очереди, а когда кончатся - расширить пул. Прикинь изврат какой!
И самое интересное, что это всё зря =)
Ну компилятор может трактовать
complex c = a + b;
как
complex c(operator+(a, cool.gif); // конструктор копирования
или как
complex c(a.re() + b.re(), a.im() + b.im()); // конструктора копирования нет
По-моему этот код должен однозначно означать:
1. Создаётся объект c конструктором по-умолчанию.
2. Вызывается operator+ который создаёт промежуточный объект complex
3. Вызывается operator= которому передаётся объект complex (лучше - по-ссылке, а то создастся ещё один объект complex при вызове оператора).
ну 1 пункт - совсем не так, вообще говоря запись Type var = value; фактически эквивалентна Type var(value); просто для удобства. (для ясности замнём здесь вопрос об explicit конструкторах).
А остальное это конечно так, но это непроизводительно, а c++ хочет быть производительным на столько, сколько можно. поэтому даже порядок вычисления аргументов не определён. Хорошо это или плохо, не знаю, но это так, это просто надо знать и учитывать.
Кстати вот 12.2.2
(standard) писал(а):[Example:
Код: Выделить всё
class X { // ... public: // ... X(int); X(const X&); ˜X(); }; X f(X); void g() { X a(1); X b = f(X(2)); a = f(a); }
Here, an implementation might use a temporary in which to construct X(2) before passing it to f() using
X’s copy-constructor; alternatively, X(2) might be constructed in the space used to hold the argument.
Also, a temporary might be used to hold the result of f(X(2)) before copying it to b using X’s copy-
constructor; alternatively, f()’s result might be constructed in b. On the other hand, the expression
a=f(a) requires a temporary for either the argument a or the result of f(a) to avoid undesired aliasing of
a. ]