Операнды оператора ?:
должны быть приведены к общему типу, который будет использоваться в результате.Когда вы используете
SetParent(p != NULL ? (HWND) *p : NULL);
, вы по существу вручную форсируете ситуацию, когда компилятор выбрал общий тип, равный HWND
.Т.е. вышеприведенный вариант эквивалентен
SetParent(p != NULL ? (HWND) *p : (HWND) NULL);
Но когда вы делаете
SetParent(p != NULL ? *p : NULL);
, правила языка работают по-другому, компилятор будет определять общий тип по-разному.В этом общем типе это не HWND
, а ваш Wnd
.Оба операнда преобразуются в Wnd
, а последний вариант интерпретируется как
SetParent(p != NULL ? *p : Wnd(NULL));
То есть, когда p
равен нулю, компилятор создает временный объект Wnd(NULL)
(используя предоставленный вами конструктор преобразования) и возвращаетэто как результат.Более того, компилятор, скорее всего, также создаст временный объект в истинной ветви (используя конструктор копирования).Результирующий временный объект затем преобразуется в тип HWND
(поскольку это то, что требуется SetParent
), поэтому все это интерпретируется как
SetParent((HWND) (p != NULL ? Wnd(*p) : Wnd(NULL)));
. Временный объект затем уничтожается сразу после вызоваSetParent
.Это уничтожение, которое вы наблюдали, за исключением того, что вы неправильно интерпретировали его как уничтожение p
.
. Причина, по которой компилятор может выбрать этот подход, заключается в том, что ваш конструктор преобразования не объявлен explicit
.Если вы объявите конструктор преобразования explicit
class Wnd {
...
explicit Wnd(HWND wnd=NULL) : m_hwnd(wnd), fake(NULL) {}
...
};
, компилятор больше не сможет использовать для неявного преобразования NULL
в Wnd
.В этом случае у компилятора не останется выбора, кроме как использовать HWND
в качестве общего типа вместо
SetParent(p != NULL ? (HWND) *p : (HWND) NULL);
, как вы и хотели.
PS Когда у вас уже есть operator HWND() const
в вашем классе нет никакого смысла в реализации идентичной неконстантной версии operator HWND()
.