Не генерируется оператор присваивания в шаблоне класса
От: MicroCephalis Россия  
Дата: 20.07.05 21:04
Оценка:
Накропал это я такой фрагмент:


template <class T, class IWrappedInterface>
class CDispinterfaceWrapper  
{
protected:
    CComQIPtr<IWrappedInterface> m_Wrapped;

    void InitCallVariables();
    {
        // разное
    }


public:
    T& operator = (const T& a_src)
    {
        InitCallVariables();
        m_Wrapped = a_src.m_Wrapped;
        return (T&)*this;
    }

    T& operator = (const IUnknown* a_pUnk)
    {
        InitCallVariables();
        m_Wrapped = a_pUnk;
        return (T&)*this;
    }
};

class CVideoEditWrapper : public CDispinterfaceWrapper<CVideoEditWrapper, _DVideoEdit>
{
public:
    CVideoEditWrapper(){InitCallVariables();}
    CVideoEditWrapper(const IUnknown* a_pSrc){ *this = a_pSrc;}
    CVideoEditWrapper(const CVideoEditWrapper& a_src){ *this = a_src;}
    virtual ~CVideoEditWrapper(){}
}

// где-то дальше
CVideoEditWrapper vew;
// еще дальше
vew = <некий IUnknown*>


Я ожидал, что при последнем присвоении будет использован непосредственно оператор присваивания из шаблона. На деле имеет место следующее: для правой части (IUnknown) компилятор сначала вызывает неявный конструктор от IUnk* (с целью, видимо, впоследствии использовать полученный объект в операторе копирования), в этом конструкторе имеет место такое же присвоение (справа IUnk*), так что снова вызывается неявный конструктор, и спустя малое время приходит stack overflow.

При этом попытка поставть breakpoint на оператор T& operator = (const IUnknown* a_pUnk) показывает, что он вообще не скомпилировался!

Если же сделать в CVideoEditWrapper'е конструктор от IUnk* типа "explicit", то при компиляции в нем вылезает ошибка "не определен оператор, принимающий в правой части const IUnk*", а оператор присваивания в шаблоне все равно не компилится.

Все эти танцы с бубном происходят в VC++ 6.0, с Микрософтским компилятором.

Шо делать?
Re: Не генерируется оператор присваивания в шаблоне класса
От: Павел Кузнецов  
Дата: 20.07.05 22:08
Оценка: 2 (1)
MicroCephalis,

>
> template <class T, class IWrappedInterface>
> class CDispinterfaceWrapper
> {
> protected:
>     void InitCallVariables();
>
> public:
>     T& operator = (const T& a_src);
>     T& operator = (const IUnknown* a_pUnk);
> };
>
> class CVideoEditWrapper : public CDispinterfaceWrapper<CVideoEditWrapper, _DVideoEdit>
> {
> public:
>     CVideoEditWrapper(){InitCallVariables();}
>     CVideoEditWrapper(const IUnknown* a_pSrc){ *this = a_pSrc;}
>     CVideoEditWrapper(const CVideoEditWrapper& a_src){ *this = a_src;}
>     virtual ~CVideoEditWrapper(){}
> }
>
> // где-то дальше
> CVideoEditWrapper vew;
> // еще дальше
> vew = <некий IUnknown*>
>

> Я ожидал, что при последнем присвоении будет использован непосредственно оператор присваивания из шаблона.

Этого не происходит, т.к. унаследованные операции присваивания, определенные в CDispinterfaceWrapper<>, скрываются операциями присваивания, неявно объявленными в классе CVideoEditWrapper.

В твоем коде есть и еще несколько неудачных моментов, среди которых использование операции присваивания *this = ... в конструкторе класса. При этом 1) переменные-члены остаются неинициализированными (в частности, похоже, отсутствует вызов InitCallVariables()); 2) operator = обычно пишется в расчете на то, что объект в левой части сконструирован, а в данном случае это не так.

> Шо делать?


Если придерживаться твоего дизайна, нужно "вручную" создать CVideoEditWrapper::operator =(CVideoEditWrapper const&) и делегирировать вызов базовому классу. С operator = (IUnknown const*) можно было бы поступить проще, написав "using CDispinterfaceWrapper<CVideoEditWrapper, _DVideoEdit>::operator =", но, т.к. VC++6, скорее всего, это переварить не в состоянии, тебе придется определить и его.


Не очень понятно, зачем, вообще, определяется класс CVideoEditWrapper вместо:
typedef CDispinterfaceWrapper<_DVideoEdit> CVideoEditWrapper;

и, соответственно, более простой реализации CDispinterfaceWrapper, с меньшим количеством хэков и ошибок...
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Не генерируется оператор присваивания в шаблоне класс
От: MicroCephalis Россия  
Дата: 20.07.05 22:56
Оценка:
Павел Кузнецов,

ПК>Этого не происходит, т.к. унаследованные операции присваивания, определенные в CDispinterfaceWrapper<>, скрываются операциями присваивания, неявно объявленными в классе CVideoEditWrapper.

С одной стороны да. Торможу. Никак не привыкну, что шаблон — это не просто кусок, который бездумно подставляется в наследуемый класс, а полноценный предок.

А с другой — почему тогда при explicit'е он оператор присваивания по умолчанию сам не генерит, но и из предка брать не желает? Да и разве генерятся операторы? Мне казалось, что только конструкторы могут по умолчанию создаваться...

ПК>В твоем коде есть и еще несколько неудачных моментов, среди которых использование операции присваивания *this = ... в конструкторе класса.

Хм. Ну, наверное... В общем, по результатам раздумья, надо сделать в базовом классе функции для выполнения копирования от разных источников, а в наследниках вызывать эти функции по мере необходимости, в копирующих ли конструкторах, в операторах ли.

ПК>Если придерживаться твоего дизайна, нужно "вручную" создать CVideoEditWrapper::operator =(CVideoEditWrapper const&)

Ага, пришлось. И со вторым тоже.

ПК>и делегирировать вызов базовому классу.

да не, к чему он там.

ПК>Не очень понятно, зачем, вообще, определяется класс CVideoEditWrapper вместо:

ПК>typedef CDispinterfaceWrapper<_DVideoEdit> CVideoEditWrapper;

Я тут упрощенно написал. В обоих классах есть еще функции, в базовом — общие для наследников, а в наследниках — те, которые в базовом приходится вызывать через приведение к наследнику.

Спасибо!
Re[3]: Не генерируется оператор присваивания в шаблоне класс
От: Павел Кузнецов  
Дата: 20.07.05 23:46
Оценка:
MicroCephalis,

> почему тогда при explicit'е он оператор присваивания по умолчанию сам не генерит, но и из предка брать не желает?


Копирующий оператор присваивания в этом случае все равно неявно объявляется, но использовать его компилятор в случае присваивания IUnknown* не может, т.к. для этого ему нужно неявно сконструировать CVideoEditWrapper из IUnknown*, что ты, поместив в объявлении соответствующего конструктора explicit, компилятору делать запретил. Убедиться в том, что копирующий оператор присваивания объявлен и доступен для использования можно попытавшись присвоить объекту CVideoEditWrapper другой объект этого же типа:
// где-то дальше
CVideoEditWrapper vew;
// еще дальше
vew = CVideoEditWrapper(); // Здесь.


> Да и разве генерятся операторы?


Да. Неявно объявляются (и в случае фактического использования определяются) следующие 4 специальные функции-члены: конструктор по умолчанию, конструктор копирования, копирующий оператор присваивания, деструктор. В этом легко убедиться, проанализировав следующий (валидный) пример:
struct S { };
int main()
{
   S s;     // конструктор по умолчанию
   S s1(s); // конструктор копирования
   s = s1;  // копирующий оператор присваивания

   // неявный вызов двух деструкторов
}
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: Не генерируется оператор присваивания в шаблоне класс
От: MicroCephalis Россия  
Дата: 21.07.05 09:06
Оценка:
Павел,

>> почему тогда при explicit'е он оператор присваивания по умолчанию сам не генерит, но и из предка брать не желает?

ПК>Копирующий оператор присваивания в этом случае все равно неявно объявляется,
Вот-вот! Копирующий оператор. А нужен-то принимающий в правой части IUnknown*. И я его в шаблоне вроде бы предлагаю. Дык не берет, нос, можно сказать, воротит! Предпочитает заниматься неявным конструированием. Вот это поведение меня и удивляет.

>> Да и разве генерятся операторы?

ПК>Да. Неявно объявляются 4 специальные функции-члены
ага, это я еще не забыл Мне показалось было из какой-то из предыдущих фраз, что генерируются любые операторы по мере необходимости, но это же чепуха, как сказала бы черная королева
Re[5]: Не генерируется оператор присваивания в шаблоне класс
От: Павел Кузнецов  
Дата: 21.07.05 15:23
Оценка: 3 (1)
MicroCephalis,

ПК>> Копирующий оператор присваивания в этом случае все равно неявно

ПК>> объявляется,

M> Вот-вот! Копирующий оператор. А нужен-то принимающий в правой

M> части IUnknown*. И я его в шаблоне вроде бы предлагаю. Дык не берет,
M> нос, можно сказать, воротит! Предпочитает заниматься неявным
M> конструированием. Вот это поведение меня и удивляет.

Функция в наследнике скрывает все одноименные функции в базовом классе.
Это же относится и к operator=. Соответственно, неявно объявленный
Derived::operator=(Derived const&)

скрывает как
Base::operator=(Derived const&)

так и
Base::operator=(IUnknown*)
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: Не генерируется оператор присваивания в шаблоне класс
От: MicroCephalis Россия  
Дата: 21.07.05 16:36
Оценка:
Павел Кузнецов,

ПК>Функция в наследнике скрывает все одноименные функции в базовом классе.

Опа. А вот это для меня ново. Я как-то был уверен, что скрываются только строго совпадающие ф-ии.
Спасибо большое!
Re[7]: Не генерируется оператор присваивания в шаблоне класс
От: Alxndr Германия http://www.google.com/profiles/alexander.poluektov#buzz
Дата: 25.07.05 17:00
Оценка:
"Строго совпадающие" (в смысле, имеющие одинаковые сигнатуры) функции как раз-таки замещаются.
Скрываются все остальные.
Re[8]: Не генерируется оператор присваивания в шаблоне класс
От: Павел Кузнецов  
Дата: 25.07.05 18:44
Оценка:
Здравствуйте, Alxndr, Вы писали:

A>"Строго совпадающие" (в смысле, имеющие одинаковые сигнатуры) функции как раз-таки замещаются. Скрываются все остальные.


Это относится только к виртуальным функциям, если под "замещаются" ты подразумеваешь перевод "override". Невиртуальные функции, даже имеющие одинаковую сигнатуру, все равно скрываются (hide).
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[9]: Не генерируется оператор присваивания в шаблоне класс
От: Alxndr Германия http://www.google.com/profiles/alexander.poluektov#buzz
Дата: 27.07.05 12:32
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

A>>"Строго совпадающие" (в смысле, имеющие одинаковые сигнатуры) функции как раз-таки замещаются. Скрываются все остальные.


ПК>Это относится только к виртуальным функциям, если под "замещаются" ты подразумеваешь перевод "override". Невиртуальные функции, даже имеющие одинаковую сигнатуру, все равно скрываются (hide).


Да, естественно, я имел в виду именно виртуальные функции
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.