Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: операции [], == и спецификатор const  (Прочитано 22414 раз)
0 Пользователей и 1 Гость смотрят эту тему.
SAA
Гость
« : 22-11-2003 13:53 » 

Начал читать на досуге "C++ Primer" Stanley Lippman. Только начал, а уже куча неясностей  Жаль
Пример:
файл IntArray.h
Код:
class IntArray
{
public:
    // .....
    bool operator==(const IntArray&) const;
    int& operator[](int);
    int size() const;
protected:
    int size_;
    int *ia_;
};

inline int IntArray::size() const
{
    return size_;
}

inline int& IntArray::operator[](int index)
{
    assert(index >= 0 && index < size_);
    return ia_[i];
}
до этого момента все ясно. Но реализация операции сравнения не написана в книге Жаль. Ладно, пробую сам написать и вот что получается.
файл IntArray.cpp
Код:
bool IntArray::operator[](const IntArray &rhs)
{
    bool result = false;
    if (size != rhs.size())
        result = true;
        for (int i = 0; int < size_; i++)
            if (ia[i] != rhs[i])    // проблемное место
            {
                result = false;
                break;
            }
    return result;
}


Компилятор на меня матом [b]error C2678: binary '[' : no operator defined which takes a left-hand operand of type 'const class IntArray' (or there is no acceptable conversion)[/b]
Ладно пишу как учит Страуструп
if (ia[i] != rhs.operator[](i))
компилятор мне в ответ  [b]error C2662: '[]': cannot convert 'this' pointer from 'const class IntArray' to 'class IntArray &'[/b]
о, это уже понятнее, хотя ничего непонятно, я ведь не трогаю этот rhs? :( Сделал финт ушами
if (ia[i] != (static_cast <IntArray> (rhs))[i])
и компилятор проглатывает. Но как-то мне это не совсем нравится. Есть ли более "правильное" решение?

И еще один вопрос. Почему спецификатор функций класса inline нельзя использовать в файлах реализации (*.cpp)?
Я, конечно, понимаю, что несколько вопросов в одном топике это моветон, но начинающим прощается.
 
  Ага
« Последнее редактирование: 21-11-2007 16:59 от Алексей1153++ » Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 22-11-2003 14:26 » 

Тут у тебя что-то все разное...
Цитата
Код:
int& operator[](int);
Код:
bool IntArray::operator[](const IntArray &rhs)
И обрати внимание на слова: error C2678: binary '[' .... Как я понимаю, индексом должено выступать число.
« Последнее редактирование: 21-11-2007 17:02 от Алексей1153++ » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
SAA
Гость
« Ответ #2 : 22-11-2003 15:52 » 

Цитата
Тут у тебя что-то все разное...
Да действительно.  Я шокирован! Пост набивал руками, а нужно было просто скопировать из файла. Так что здесь обыкновенная опечатка, суть вопроса не меняющая.

Код:
bool IntArray::operator==(const IntArray &rhs) const
{
bool result = false;
if (size_ == rhs.size())
result = true;
for (int i = 0; i < size_; i++)
{
// if (ia_[i] != rhs[i])                             < - было
if (ia_[i] != (static_cast <IntArray> (rhs))[i])   //< - исправил
{
result = false;
break;
}
}
return result;
}
« Последнее редактирование: 21-11-2007 17:03 от Алексей1153++ » Записан
Serega
Гость
« Ответ #3 : 22-11-2003 20:08 » 

Добавь
Код:
inline const int& IntArray::operator[](int index) const
{
    assert(index >= 0 && index < size_);
    return ia_[i];
}
« Последнее редактирование: 21-11-2007 17:04 от Алексей1153++ » Записан
Serega
Гость
« Ответ #4 : 22-11-2003 20:11 » 

И оператор== попроще, так понятнее будет
Код:
bool IntArray::operator==(const IntArray &rhs) const
{
if( size_ != rhs.size() ) return false;
for(int i = 0; i < size_; i++)
{
if( ia_[i] != rhs[i] ) return false;
}
return true;
}
« Последнее редактирование: 21-11-2007 17:05 от Алексей1153++ » Записан
SAA
Гость
« Ответ #5 : 23-11-2003 04:45 » 

2 Serega
Да, действительно нужно было перегрузить оператор [], и тогда все заработало. Просто мне еще трудно переварить, что оператор, по сути, является той же самой функцией-членом, которую можно смело перегружать.
Цитата
И оператор== попроще, так понятнее будет
Цитата
bool IntArray::operator==(const IntArray &rhs) const
{
   if( size_ != rhs.size() ) return false;
   for(int i = 0; i < size_; i++)
   {
      if( ia_ != rhs ) return false;
   }
   return true;
}

А ничего, что у тебя выход из процедуры в трех местах? А мне в свое время вдолбили, что выход из процедуры должен быть в одном месте, и goto это плохо.
А как насчет второго вопроса?

Большое спасибо за ответы. // "Продолжим читать далее", - сказал SAA, вытаскивая книгу из-за дивана. Улыбаюсь
Записан
Serega
Гость
« Ответ #6 : 23-11-2003 07:28 » 

return это не goto и пользоваться им можно и нужно, и это совсем не плохо
goto плох тем что возможно прыгнуть за пределы функции

спецификатор inline какраз предназначен для того, чтобы использовать его в файлах .cpp, т.к. если код написан в .h (в определении класса) то он по умолчанию является inline
Записан
SAA
Гость
« Ответ #7 : 23-11-2003 15:22 » 

Цитата
return это не goto и пользоваться им можно и нужно, и это совсем не плохо
goto плох тем что возможно прыгнуть за пределы функции
Понятно. Беру на вооружение.  8)
Цитата
спецификатор inline какраз предназначен для того, чтобы использовать его в файлах .cpp, т.к. если код написан в .h (в определении класса) то он по умолчанию является inline
Работаю в среде VS6.0
Код:
// файл foo.h
#ifndef FOO_H
#define FOO_H

class foo
{
public:
foo():i(0){};
int f();
private:
int i;
};

#endif FOO_H
Код:
// файл foo.cpp
#include "foo.h"

inline int foo::f()
{
return i;
}
Код:
// main.cpp
#include <iostream>
#include "foo.h"

int main()
{
std::cout << foo().f();
return 0;
}

Линкер :error LNK2001: unresolved external symbol "public: int __thiscall foo::f(void)" (?f@foo@@QAEHXZ)
Может какие ключи забыл выставить?Жаль
« Последнее редактирование: 21-11-2007 17:07 от Алексей1153++ » Записан
Alf
Гость
« Ответ #8 : 23-11-2003 19:51 » 

Цитата: SAA
Код:
// main.cpp
#include <iostream>
#include "foo.h"

int main()
{
std::cout << foo().f();
return 0;
}

Линкер :error LNK2001: unresolved external symbol "public: int __thiscall foo::f(void)" (?f@foo@@QAEHXZ)
Может какие ключи забыл выставить?Жаль
Во-первых, перед тем, как использовать методы объекта класса foo, следует создать его экземпляр.
Во-вторых, круглые скобки после имени объекта при вызове его метода не нужны.
Если же есть необходимость вызвать метод класса без создания экземпляра, следует объявить метод как статический (соблюдая все положенные в этом случае предосторожности, разумеется).
« Последнее редактирование: 21-11-2007 17:08 от Алексей1153++ » Записан
Anonymous
Гость
« Ответ #9 : 24-11-2003 01:09 » 

Цитата: SAA
Цитата
Код:
// файл foo.cpp
#include "foo.h"

inline int foo::f()
{
return i;
}
Код:
// main.cpp
#include <iostream>
#include "foo.h"

int main()
{
std::cout << foo().f();
return 0;
}

Линкер :error LNK2001: unresolved external symbol "public: int __thiscall foo::f(void)" (?f@foo@@QAEHXZ)
Может какие ключи забыл выставить?Жаль

Да нет, ты не понял. inline может употребляться только в .h-файлах. Твой foo.cpp при компиляции main.cpp не включается -- в нём inline использовать нельзя. Либо убери его вообще (в foo.h пиши int f (int i) {return i;}), либо убери inline.

С уважением -- Смоляное Чучелко
« Последнее редактирование: 21-11-2007 17:09 от Алексей1153++ » Записан
Anonymous
Гость
« Ответ #10 : 24-11-2003 01:12 » 

Цитата: Anonymous
Цитата
(в foo.h пиши int f (int i) {return i;})


Виноват. Разумеется, int f (void) {return i;}

С уважением -- Смоляное Чучелко
Записан
SAA
Гость
« Ответ #11 : 24-11-2003 06:02 » 

2 Alf
Цитата
Во-первых, перед тем, как использовать методы объекта класса foo, следует создать его экземпляр.
Вот здесь ты ошибаешься.
Код:
std::cout << foo().f();
Этот кусочек кода эквивалентен, следующему коду
Код:
{
    foo tmp;
    std::cout << tmp.f();
}
т.е. время жизни объекта foo ограниченно одной строкой. Кстати, я умею отличать ошибки компилятора от ошибок линкёра (или линковщика, не знаю как правильно), а ты? Ага

2 Смоляное Чучелко
Цитата
inline может употребляться только в .h-файлах.
Абсолютно точно уверен, что inline можно применять и в файлах *.cpp, если все описание класса находится в нем.  Отлично
Цитата
Твой foo.cpp при компиляции main.cpp не включается -- в нём inline использовать нельзя
Попробую уточнить. Этот файл включается в процесс компиляции, просто компилятор, подлюка, не включает функции с этим спецификатором в объектный код.
Цитата
Либо убери его вообще (в foo.h пиши int f (int i) {return i;}), либо убери inline.
Пытаюсь отделить реализацию от интерфейса, пока не выходит Жаль Конечно, можно было бы предоставить компилятору самому определять, где нужен inline, а где нет, но я тоже хочу пользоваться этим средством.

Подсчет голосов по второму вопросу 1:1. Жду разъяснений.
« Последнее редактирование: 21-11-2007 17:12 от Алексей1153++ » Записан
Serega
Гость
« Ответ #12 : 24-11-2003 17:58 » 

Проблема вот в чем:
что бы функуция была inline необходим её код в том модуле где она используется (иначе просто нечего подставлять:)
если кода нет, то насколько я понял компилятор оставляет ссылку линкеру, а тот честно не находит этой функции т.к. она обьявлена как inline
Записан
SAA
Гость
« Ответ #13 : 25-11-2003 16:33 » 

Посмотрел у Страуструпа главу "Исходные файлы и программы", пока не смог переварить. Ладно, делаю предварительные выводы: функции-члены классов со спецификатором inline должны находится либо в описании класса, либо в том же файле. Пока этого для меня хватит.

Спасибо всем за ответы.
Записан
Migmile
Помогающий

ru
Offline Offline

« Ответ #14 : 27-11-2003 14:04 » 

Цитата

goto плох тем что возможно прыгнуть за пределы функции

что-то я не понял - это как (или куда)Не понял
Записан
Sashok
Молодой специалист

us
Offline Offline
Пол: Мужской

« Ответ #15 : 27-11-2003 16:39 » 

Цитата: Migmile
Цитата

goto плох тем что возможно прыгнуть за пределы функции

что-то я не понял - это как (или куда)Не понял
Для goto выйти за пределы функции невозможно. Вероятно, Serega имел ввиду setjmp() - longjmp().
Записан

Если бы окружающие нас объекты содержали столько же ошибок, сколько программы, цивилизация обрушилась бы от первого порыва ветра...
NetRaider
Гость
« Ответ #16 : 02-12-2003 07:53 » 

Цитата: SAA
Линкер :error LNK2001: unresolved external symbol "public: int __thiscall foo::f(void)" (?f@foo@@QAEHXZ)
Может какие ключи забыл выставить?

Это происходит потому, что inline-функция должна быть определена в каждой единице трансляции, в котрой она используется.

Цитата: Гость
Да нет, ты не понял. inline может употребляться только в .h-файлах.

Цитата: SAA
Ладно, делаю предварительные выводы: функции-члены классов со спецификатором inline должны находится либо в описании класса, либо в том же файле.

Любая функци может быть определена со спецификатором inline. И неважно где она находится - в .h, или .cpp файле, так как к моменту компиляции никаких заголовочных файлов нет -  препроцессор всех их повключал в *.cpp-файлы. Главное чтобы такая функция была поределена в каждой единице трансляции.

Цитата: SAA
Цитата
Во-первых, перед тем, как использовать методы объекта класса foo, следует создать его экземпляр.  
Вот здесь ты ошибаешься.

Для вызова нестатических функций класса необходим экземпляр этого класса.

Цитата: SAA
Код:
std::cout << foo().f();
Этот кусочек кода эквивалентен, следующему коду
Код:
{
    foo tmp;
    std::cout << tmp.f();
}

т.е. время жизни объекта foo ограниченно одной строкой.

Это не эквивалентные куски кода. В первом случае время жизни действительно ограничено одной строкой, так как безымянный объект класса используется как агрумент оператора '<<', после чего благополучно умирает. Во втором случае время жизни объекта закончится при выходе за '}'.
« Последнее редактирование: 21-11-2007 17:13 от Алексей1153++ » Записан
Mfcer__
Команда клуба

ru
Offline Offline

« Ответ #17 : 02-12-2003 12:20 » 

Цитата

"C++ Primer" Stanley Lippman

А что за книжка? Можно ее где - нибудь скачать? (Или купить В Питере?)
Записан
SAA
Гость
« Ответ #18 : 02-12-2003 15:03 » 

Что такое inline, и с чем его едят?
В общем, мелкие кусочки разрозненной информации начинают собираться в единое целое. Вот что у меня получилось.
Спецификатор inline подсказывает компилятору, чтобы он пытался генерировать в месте вызова, код вызываемой функции. Именно подсказывает, а не заставляет, так как тело функции может содержать вызовы самой себя (рекурсия). Функция с этим спецификатором должны быть определена во всех единицах трансляции, где она используется. Насколько я понимаю, определение inline - функции в каждой единице трансляции необходимо компилятору для того, чтобы выполнить подстановку, если он на это решится. Если же подстановка не выполняется, то, скорее всего, вызывается из той единицы трансляции, которая первой попадет линкеру. Так почему же все-таки умные люди советуют такие функции выносить в файлы-заголовки(*.h). А вот почему:

Код:
// file1.cpp
inline int f() { return 1; }
int g() { return f(); }

// file2.cpp
#include <stdio.h>

inline int f() { return 2; } // определения этой функции требует стандарт
extern int g();

int main()
{
printf("%i %i\n", g(), f());
return 0;
}
Пример, конечно, надуманный, но все-таки.
На выходе получим:
1 2
Для того чтобы такого не было нужно взять за правило выносить такие функции в файлы заголовки.
Кстати результат подтверждает мою догадку, о том для чего нужно определение функции со спецификатором inline во всех единицах трансляции, где она используется.
Выключим inline-подстановки (для VS6.0 опция /Ob1) и включим минимизацию кода (для VS6.0 опция /O1). Перекомпилировав, и выполнив программу, получим:
1 1
что подтверждает гипотезу о вызове функции из первой попавшейся линкеру единицы компиляции.
Вроде бы все сказал, что хотел. Может быть, у кого-нубудь есть, чем дополнить? Хотелось бы выслушать.
« Последнее редактирование: 21-11-2007 17:16 от Алексей1153++ » Записан
SAA
Гость
« Ответ #19 : 02-12-2003 15:11 » 

Цитата: Mfcer__
Цитата

"C++ Primer" Stanley Lippman

А что за книжка? Можно ее где - нибудь скачать? (Или купить В Питере?)


здесь, один из лучших ресурсов по тематике C/C++

P.S.  Советую потратиться на бумажный вариант. IMHO все же "живая" книга намного приятней и полезней чем её электронный вариант. 8)
Записан
Смоляное Чучелко
Гость
« Ответ #20 : 04-12-2003 01:16 » 

Цитата: NetRaider
Цитата: SAA
Код:
std::cout << foo().f();
Этот кусочек кода эквивалентен, следующему коду
Код:
{
    foo tmp;
    std::cout << tmp.f();
}

т.е. время жизни объекта foo ограниченно одной строкой.

Это не эквивалентные куски кода. В первом случае время жизни действительно ограничено одной строкой, так как безымянный объект класса используется как агрумент оператора '<<', после чего благополучно умирает. Во втором случае время жизни объекта закончится при выходе за '}'.

С чего бы ему в первом случае ограничиваться одной строкой? Он создаётся в оной строке и живёт, пока не умрёт -- а это случится в конце объемлющего блока. А где оный конец -- автор ведает.

С уважением -- Смоляное Чучелко
« Последнее редактирование: 21-11-2007 17:17 от Алексей1153++ » Записан
NetRaider
Гость
« Ответ #21 : 04-12-2003 03:22 » 

Цитата

С чего бы ему в первом случае ограничиваться одной строкой? Он создаётся в оной строке и живёт, пока не умрёт -- а это случится в конце объемлющего блока. А где оный конец -- автор ведает.


Ничего подобного. Время жизни временного объекта определяется концом полного выражения.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines