Перегрузка оператора и конструктор копии
От: Jamais Vu  
Дата: 25.12.02 16:54
Оценка:
Я бы хотел уточнить некоторые моменты, связанные с вызовом конструктора копии и обычного конструктора. У меня есть класс, содержащий указатель на динамически выделяемую память. Я включил в конструктор и деструктор соответствующие блоки. Также перегрузил оператор присваивания и явно написал конструктор копии чтобы избежать побитового копирования по умолчанию. Ввел необходимые арифметические операции как члены класса:
classname classname::operator+(const classname &right) {
classname temp(param);
...
return temp;
}
classname classname::operator*(const classname &);//реализация аналогично +
Насколько я понимаю при обращении объекту класса первый раз вызывается конструктор, а при выходе из области его видимости — деструктор. Просто протестировал следующую строчку:
classname A(param), B(param), C(param);
A=B*C+A;
И посмотрел в каком порядке вызываются кон/деструкторы. Оказалось что деструкторы вызываются не сразу после выхода из функции перегруженного оператора и использовании программой возвращаемого им значения а только после обработки знака равенства. Вот в этот момент и вызываются все необходимые деструкторы для удаления промежуточных результатов вычислений.
На эту в общем-то логичную штуку наткнулся после попытки выяснить когда же все-таки вызывается конструктор копии объекта. Два варианта понятны, а именно: когда производится инициализация свежеобъявленного объекта класса другим объектом (classname A=B), и когда имеет место передача объекта в функцию по значению. Но ещё он может вызываться при возвращении копии локального объекта, объявленного в какой-нибудь функции. Идея понятна: локальный умирает при выходе из функции а копия возвращается. Правда бывает так не всегда. В частности в моей функции умножения он вызывается, а в функции сложения нет (деструктор вызывается при обработке знака равенства). Хотелось бы уточнить когда же все-таки он вызывается и от чего это зависит... Это был вопрос. :)
И второй вопрос по поводу перегрузки операторов.
Можно ли каким-нибудь хитрым ходом сделать перегрузку псевдооператора [][] (двойной массив), которого нет, через [], который есть. Вариант [x,y] понятен но хотелось бы чтобы сохранился вид [x][y]. Это тоже был вопрос к многоуважаемому сообществу программистов. :)
Re: Перегрузка оператора и конструктор копии
От: comer США http://getboost.codeplex.com/
Дата: 25.12.02 18:27
Оценка: 1 (1)
Здравствуйте, Jamais Vu, Вы писали:

1. Для начала покрасим твой текст:
classname classname::operator+(const classname &right) {
classname temp(param);
...
return temp;
}

classname classname::operator*(const classname &);//реализация аналогично +

classname A(param), B(param), C(param);
A=B*C+A;


JV>И посмотрел в каком порядке вызываются кон/деструкторы. Оказалось что деструкторы вызываются не сразу после выхода из функции перегруженного оператора и использовании программой возвращаемого им значения а только после обработки знака равенства.

Правильно, деструкотр присваиваемого объекта обязан вызывать после операции, в данном случае присваивания.
Если было бы не так, тогда что бы мы присваивали бы после работы деструктора ?

JV>Вот в этот момент и вызываются все необходимые деструкторы для удаления промежуточных результатов вычислений.

JV>На эту в общем-то логичную штуку наткнулся после попытки выяснить когда же все-таки вызывается конструктор копии объекта.
Компилятор может оптимизировать и считать твой объект classname temp(param) в оператора * или + тем временным объектом в который расчитываеться результат операции * или +.

JV>Можно ли каким-нибудь хитрым ходом сделать перегрузку псевдооператора [][] (двойной массив), которого нет, через [], который есть. Вариант [x,y] понятен но хотелось бы чтобы сохранился вид [x][y]. Это тоже был вопрос к многоуважаемому сообществу программистов.

Можно сделать промежуточный класс который будет возвращать оператор[] твоего класса, и который сам будет иметь оператор[].

Например:
class YourClass
{
    int a[5][5];
    
    class Tmp
    {        
        YourClass &your_class;
        int i;
        
        Tmp(YourClass &your_class_, int i_): your_class(your_class_), i(i_)
        {
        }
        
        Tmp(const Tmp &);
        
        friend class YourClass;
        
    public:
    
        int &operator[](int j) 
        { 
            return your_class.a[i][j]; 
        }
    };
    
public:

    Tmp operator[](int i) 
    {
        return Tmp(*this, i);
    }
};

int main() 
{ 
    YourClass y;
    
    y[3][4]=5;
    int m=y[3][4];

}
getboost.codeplex.com
citylizard.codeplex.com
Re: Перегрузка оператора и конструктор копии
От: jazzer Россия Skype: enerjazzer
Дата: 25.12.02 18:44
Оценка:
Здравствуйте, Jamais Vu, Вы писали:

JV>Хотелось бы уточнить когда же все-таки он вызывается и от чего это зависит... Это был вопрос.


Он вызывается после того, как объект перестал быть нужен (и по крайней мере до начала следующей инструкции, если на какой-либо временный объект не была заведена константная ссылка). Подробности смотри в Стандарте (12.2).
Еще надо помнить, что компилятор имеет право соптимизировать возвращение локальной переменной по значению, обойдясь без копирования.

JV>И второй вопрос по поводу перегрузки операторов.

JV>Можно ли каким-нибудь хитрым ходом сделать перегрузку псевдооператора [][] (двойной массив), которого нет, через [], который есть.
тебе нужен один оператор[], который вернет объект некоего левого класса, в котором будет храниться, например, данный х и ссылка на матрицу, а у него определить свой оператор[], который уже будет возвращать элемент.

JV>Вариант [x,y] понятен но хотелось бы чтобы сохранился вид [x][y]. Это тоже был вопрос к многоуважаемому сообществу программистов.


он, конечно, понятен, но в С++ невозможен, ибо оператор[] воспринимает только один аргумент.
Если ты хочешь писать два индекса в скобках, переопредели оператор().
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Спасибо за ответы
От: Jamais Vu  
Дата: 26.12.02 08:13
Оценка:
Особенно за перегрузку [][]. Попробую.
А вот вызов деструктора после операции присваивания это видимо особенность компиллятора VC++6. Потому что даже в более длинной цепочке операций, скажем:

A=B+C*D-F+G;

деструкторы промежуточных результатов вызываются только после обработки =, а не после использования возвращаемого значения в следующей операции.
To` раз спасибо за консультацию.
Re[3]: О разрушении временных объектов
От: Znow  
Дата: 26.12.02 08:19
Оценка:
Здравствуйте, Jamais Vu, Вы писали:

JV>деструкторы промежуточных результатов вызываются только после обработки =, а не после использования возвращаемого значения в следующей операции.


Правило очень простое: временные объекты разрушаются по завершении вычисления полного выражения, при вычислении которого они были созданы, в порядке, обратном порядку их создания.
Re[2]: Перегрузка оператора и конструктор копии
От: Bell Россия  
Дата: 27.12.02 07:47
Оценка:
Здравствуйте, comer, Вы писали:

C>Можно сделать промежуточный класс который будет возвращать оператор[] твоего класса, и который сам будет иметь оператор[].

...

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

template <typename T>
class myarr
{
   T* m_data;
   int m_nColumns;
   int m_nRows;//Нужен только для контроля корректности индексов
public:
...
   T* operator[] (size_t nRow) { assert(nRow < m_nRows); return m_data + nRow*m_nColumns; }
};


минус этого подхода — невозможно проверить второй индекс в выражении [][]
Любите книгу — источник знаний (с) М.Горький
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.