Ответ 1
Параметр ppObj
для RemoveObj является ссылкой на родительский *. Что, если метод RemoveObj()
заменил указатель указателем на новый объект Parent
? Когда метод вернет ваш, pCObj
Child*
больше не будет указывать на объект Child
.
Кто-нибудь знает, почему это дает ошибку компилятора? Я пробовал VS 2005 и Codewarrior:
class Parent {
protected:
int m_Var;
public:
Parent() : m_Var(0) {}
virtual ~Parent() {}
void PubFunc();
};
class Child : public Parent {
protected:
bool m_Bool;
public:
Child() : m_Bool(false) {}
virtual ~Child() {}
void ChildFunc();
};
void RemoveObj(Parent *& ppObj)
{
delete ppObj;
ppObj = 0;
}
int main()
{
Parent* pPObj = 0;
Child* pCObj = 0;
pPObj = new Parent();
pCObj = new Child();
RemoveObj(pPObj);
RemoveObj(pCObj);
return 1;
}
Visual studio говорит:
refptr.cpp(33): ошибка C2664: 'RemoveObj': невозможно преобразовать параметр 1 от "Ребенок *" до "Родительский" и "
Спасибо
Параметр ppObj
для RemoveObj является ссылкой на родительский *. Что, если метод RemoveObj()
заменил указатель указателем на новый объект Parent
? Когда метод вернет ваш, pCObj
Child*
больше не будет указывать на объект Child
.
Из стандарта С++ (1998)
За исключением контекста инициализация с помощью определяемых пользователем (13.3.1.4, 13.3.1.5), a хорошо сформированное неявное преобразование последовательность является одной из следующих формы: стандартное преобразование последовательность (13.3.3.1.1), пользователь определяется...
13.3.3.1.1
Не более одного обращения от каждого категория допускается в одном стандартная последовательность преобразования
Таким образом, С++ не может преобразовать неявно два раза подряд: от указателя к указателю, а затем снова от указателя.
Чтобы очистить это, рассмотрите такое объявление RemoveObj
void RemoveObj(Parent ** ppObj)
И вы увидите эту ошибку
error: invalid conversion from 'Child**' to 'Parent**'
Вы должны использовать явное преобразование, например
RemoveObj((Parent**)&pCObj);
RemoveObj((Parent*&)&pCObj);
или изменить
void RemoveObj(Parent *& ppObj)
к
void RemoveObj(Parent * ppObj)
или
template <typename T>
void RemoveObj(T *& pObj)
{
delete pObj;
pObj = 0;
}
ppobj - это ссылка на указатель. * ppobj разделяет то, что указывает переменная, поэтому вы получаете переменную указателя.
Поскольку разыменование не соответствует правильному типу, вы видите ошибку.
Указатель на ссылку позволяет изменять значение указателя в функции. Как отметил Michael Burr, будет возможность назначить неверную ссылку на класс и вернуть ее. Представьте себе всю вашу программу неправильно, используя * pchickens as * peggs:)
Я думал, что стоит добавить (хотя явно не то, что вы просили): Мое предпочтение полиморфной реализации состоит в том, чтобы перемещать общие функции внутри как методы. Если все они используют функцию, просто добавьте ее в базовый класс.
Тогда в любом случае вы могли бы просто позвонить Foo- > Bar() и добиться желаемого результата. Но для конкретного примера реализации, который вы даете, просто удалить Foo вызовет соответствующий деструктор.
Это не авторитетно, но я считаю, что проблема заключается в том, что полиморфная природа классов С++ не распространяется на их указатели; то, что вы ожидаете сделать здесь, заключается в том, чтобы Child *
был добавлен к Parent *
; в то время как вы можете отличить Child
до Parent
, вы не можете использовать указатель reference. То есть, классы являются полиморфными, но указатели на классы не используются в качестве ссылок. Это по той причине, что Майкл Берр дает выше; Child *
подразумевает определенную структуру памяти, которую не имеет Parent *
.