Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Вернуть объект класса 
:(
    Опции темы
efpies
Дата 24.11.2010, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 20.6.2009
Где: СПб

Репутация: нет
Всего: нет



Здравствуйте. Столкнулся с такой проблемой: нужно как-то вернуть объект класса.

вот, что есть

Код

// Конструктор копирования
Matrix::Matrix (const Matrix& X)
{
    Create  (X.rows_, X.cols_);

    for (unsigned i = 0; i < this->rows_; i++)
        for (unsigned j = 0; j < this->cols_; j++)
            this->values_[i][j] = X.values_[i][j];
}

// Транспонирование
Matrix& Matrix::Transpose()
{
    Matrix* temp = new Matrix(*this);

    temp->TransposePermanent();

    return *temp;
}

// Транспонирование
void Matrix::TransposePermanent()
{
    double** new_values = new double*[cols_];

    for (unsigned i = 0; i < cols_; i++)
    {
        new_values[i] = new double[rows_];

        for (unsigned j = 0; j < rows_; j++)
            new_values[i][j] = values_[j][i];
    }

    Erase ();

    unsigned t = rows_;
    rows_ = cols_;
    cols_ = t;

    values_ = new_values;
}

void main ()
{
    Matrix  c(3,2);
    Matrix *d;

    c.Print();

    *d = c.Transpose();
    d->Print();
}

При попытке вывода - Access violation, да и в значениях rows_ и cols_ мусор. Внутри Transpose всё выводит нормально, да и конструктор копирования вызывается.

То ли значение возвращает Transpose? Как быть, если надо вернуть объект и присвоить его адрес указателю?
PM MAIL   Вверх
triclosan
Дата 24.11.2010, 15:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 515
Регистрация: 18.8.2006

Репутация: 2
Всего: 12



имхо как-то плохо выглядит.

если так 
Код


int main ()
{
    Matrix  c(3,2);
    Matrix *d = new Matrix();
    c.Print();
    *d = c.Transpose();
    d->Print();
    return 0;

}



вообще-то лучше избегать прямого использования указателей и динамической памяти тем более в методах-геттерах, ведь у вас же не системное ПО, а прикладное. 


Это сообщение отредактировал(а) triclosan - 24.11.2010, 15:23
PM MAIL   Вверх
efpies
Дата 24.11.2010, 15:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 20.6.2009
Где: СПб

Репутация: нет
Всего: нет



Вопрос в удобстве: ведь проще объявить указатель в начале функции и потом его задействовать (хотя это плохо, говорят), чем объявить статичный объект и тут же присвоить. Может, я и ошибаюсь, конечно.

Ваша конструкция не сработала, зато сработала вот такая:
Код

Matrix *d;
d = &(c.Transpose());

Почему это так? Я разве не возвращаю Matrix&?
PM MAIL   Вверх
triclosan
Дата 24.11.2010, 16:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 515
Регистрация: 18.8.2006

Репутация: 2
Всего: 12



Matrix& Matrix::Transpose() возвращает объект по ссылке.

В вашем коде получаете объект по ссылке, далее берете его адрес и пишите в указатель. 
PM MAIL   Вверх
bsa
Дата 24.11.2010, 16:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



efpies, не надо возвращать таким образом. потому что совсем не очевидно, что после этого необходимо присвоить адрес результата указателю, а в конце работы сделать delete. лучше сделай так:
Код
Matrix Matrix::Transpose()
{
    Matrix temp(*this);
    temp.ransposePermanent();
    return temp;
}
Утечек памяти хотя бы не будет.

Кстати, а метод Erase у тебя rows_ и cols_ случаем не обнуляет?

Это сообщение отредактировал(а) bsa - 24.11.2010, 16:21
PM   Вверх
WhKitten
Дата 24.11.2010, 16:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 24.11.2010

Репутация: нет
Всего: нет



Цитата(efpies @ 24.11.2010,  15:56)
Ваша конструкция не сработала, зато сработала вот такая:
Код

Matrix *d;
d = &(c.Transpose());

Почему это так? Я разве не возвращаю Matrix&?

Помоему Вы путает ссылки и указатели это разные вещи.
Код

Matrix *d; // неинициализированный указатель на Matrix
Matrix &d = c.Transpose(); // ссылка на Matrix
 
поэтому код:
Код

Matrix *d;
*d = c.Transpose();

Трактуется как: выполнить оператор присваивания для объекта Matrix по адресу d. Поскольку d неинициализированна, то это вызывает Access Violation. Мы пытаемся выполнить оператор присваивания для несуществующего объекта класса.
Кстати, если бы Вы написали так:
Код

Matrix *d = c.Transpose();

то компилятор бы обнаружил вашу ошибку. Всегда старайтесь инициализировать переменные, как можно раньше.
PM MAIL   Вверх
bsa
Дата 24.11.2010, 16:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 85
Всего: 196



Цитата(WhKitten @  24.11.2010,  17:19 Найти цитируемый пост)
выполнить оператор присваивания для объекта Matrix по адресу d.

Ну ты сказал...
На самом деле все проще: "присвоить объекту, находящемуся в ячейке памяти, на которую указывает d, значение возвращенное c.Transpose()". Под словом "присвоить" имеется в виду "вызвать оператор присваивания".
PM   Вверх
efpies
Дата 24.11.2010, 16:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 20.6.2009
Где: СПб

Репутация: нет
Всего: нет



Цитата(bsa @  24.11.2010,  16:17 Найти цитируемый пост)
Кстати, а метод Erase у тебя rows_ и cols_ случаем не обнуляет?

Нет, он просто удаляет double** values и присваивает ему NULL

Цитата(bsa @  24.11.2010,  16:17 Найти цитируемый пост)
лучше сделай так:

А что присваивать *d в таком случае? Если &(c.Transpose()), то Access violation на выводе, но rows_ и cols_ в порядке.
PM MAIL   Вверх
xvr
Дата 24.11.2010, 17:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Если вам нужно вернуть объект и присвоить его в переменную, то так и пишите:
Код

Matrix Matrix::Transpose()
{
    Matrix temp(*this);
    temp.TransposePermanent();
    return temp;
}

void main ()
{
    Matrix  c(3,2);
    Matrix d;
    c.Print();
    d = c.Transpose();
    d.Print();
}
И не надо накручивать вокруг всяких закорючек (* и &), смысла которых не понимаете  smile 

PM MAIL   Вверх
WhKitten
Дата 24.11.2010, 17:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 24.11.2010

Репутация: нет
Всего: нет



Цитата(xvr @ 24.11.2010,  17:40)
Если вам нужно вернуть объект и присвоить его в переменную, то так и пишите

Только тогда надо будет определить оператор присваивания, аналогичный копирующему конструктору, за тем исключением, что он должен ещё выполнять очистку старого значения:
Код

Matrix& Matrix::operator= (const Matrix& obj)
{
    if (&obj != this) {
        // очистка
        // присвоение нового значения
    }
    return *this;
}


Но мне кажется проблема уже в чём то другом. &(c.Transpose()) возвращает адрес переменной в куче, а если delete не вызывалось, то она должна быть проинициализирована, о чём и говорит, что rows_ и cols_ в порядке. Может во время выполнения d->Print() выполняется доступ к несуществующему индексу?

Это сообщение отредактировал(а) WhKitten - 24.11.2010, 17:53
PM MAIL   Вверх
WhKitten
Дата 24.11.2010, 18:14 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 24.11.2010

Репутация: нет
Всего: нет



И ещё вариант. Вместо:
Код

 double** values_

использовать:
Код

  std::vector<std::vector<double>> values_;

тогда отпадёт надобность и в операторе присваивания и в копирующем конструкторе. И с указателями путаницы будет меньше.
PM MAIL   Вверх
efpies
Дата 24.11.2010, 19:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 20.6.2009
Где: СПб

Репутация: нет
Всего: нет



Цитата(xvr @  24.11.2010,  17:40 Найти цитируемый пост)
И не надо накручивать вокруг всяких закорючек (* и &), смысла которых не понимаете

Ну, возможно, стоит попробовать научиться понимать их смысл, не так ли? Операция & - взять адрес, * - взять по адресу? В то же время & - ссылка, а * - указатель? Нет?

Цитата(xvr @  24.11.2010,  17:40 Найти цитируемый пост)
Matrix Matrix::Transpose(){    Matrix temp(*this);    temp.TransposePermanent();    return temp;}

Да и вообще говоря, перегруженное сложение не вызовется, если не возвращать Matrix&, ибо not implemented.

Цитата(WhKitten @  24.11.2010,  17:52 Найти цитируемый пост)
о чём и говорит, что rows_ и cols_ в порядке

На самом деле, они были не в порядке, это моя ошибка: они становились равными 0.

Цитата(WhKitten @  24.11.2010,  17:52 Найти цитируемый пост)
Только тогда надо будет определить оператор присваивания

Оператор присваивания перегружен. Другое дело, что он вообще не вызывается, а вместо него вызывается конструктор копирования. Да и нужен ли этот оператор теперь? Что-то из них, выходит, можно убрать.

В итоге получается вот что:
1. Транспонирование проходит на "ура".
2. Копирование не работает. Копируется 0, вернее. Потому что вызывается деструктор. Не оттого ли, что в Transpose объект локален? Хотя это может быть бредом.

Цитата(WhKitten @  24.11.2010,  18:14 Найти цитируемый пост)
std::vector

До этого, видимо, пока рановато)
PM MAIL   Вверх
WhKitten
Дата 24.11.2010, 19:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 24.11.2010

Репутация: нет
Всего: нет



Цитата(efpies @ 24.11.2010,  19:06)
Цитата(xvr @  24.11.2010,  17:40 Найти цитируемый пост)
И не надо накручивать вокруг всяких закорючек (* и &), смысла которых не понимаете

Ну, возможно, стоит попробовать научиться понимать их смысл, не так ли? Операция & - взять адрес, * - взять по адресу? В то же время & - ссылка, а * - указатель? Нет?

Только надо отличать, когда это & объявление ссылки, а когда взятие адреса.
Код

Matrix& func1() { static Matrix x1; return x1; } // возвращает ссылку на x1
Matrix* func2() { static Matrix x2; return &x2; } // возвращает указатель на x2
Matrix &y = func1(); // y ссылка на x1
Matrix *z = *func1(); // ОШИБКА: для Matrix не определён оператор *
Matrix *z = &func1(); // z указатель на x1
*z = func2(); // ОШИБКА: нельзя преобразовать Matrix* в Matrix
z = func2(); // ОК, z указатель на x2
z = &func1(); // z указатель на x1
*z = *func2(); // присвоить x1 значение x2
z = y; // ОШИБКА: нельзя преобразовать Matrix в Matrix*
*z = y; // OK

PM MAIL   Вверх
triclosan
Дата 24.11.2010, 19:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 515
Регистрация: 18.8.2006

Репутация: 2
Всего: 12



Цитата(efpies @  24.11.2010,  19:06 Найти цитируемый пост)
До этого, видимо, пока рановато) 

Вы не правы, как раз в этом направлении стоит углублять изучение С++, а мрачных конструкций new - delete по возможности пока избегать, вы же не контроллеры программируете. Пусть вас не вводит в заблуждение, что во многих книгах по с++ для новичков new - delete рассматривается как полноценный инструмент, всему свое время. Для правильного и глубокого понимания std::* могу порекомендовать 
Николай Джосьютис, C++. Стандартная библиотека, Питер, 2004.
PM MAIL   Вверх
xvr
Дата 24.11.2010, 20:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(efpies @  24.11.2010,  19:06 Найти цитируемый пост)
Оператор присваивания перегружен. Другое дело, что он вообще не вызывается, а вместо него вызывается конструктор копирования. Да и нужен ли этот оператор теперь? Что-то из них, выходит, можно убрать.
Нужны оба. Они должны делать приблизительно одно и тоже, а заменить их кем то одним увы не получится - они вызываются в разных случаях (и в обоих случаях надо делать корректное копирование)


PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0723 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.