2009-04-10 55 views
2

我正在寻找一种合适的方式来清理我的指针。 下面的示例代码:C++多态不支持指针指针

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) 
{ 
    *ppObj->PubFunc(); 
    delete *ppObj; 
    ppObj = NULL; 
} 

int main() 
{ 
    Parent* pPObj = NULL; 
    Child* pCObj = NULL; 
    pPObj = new Parent(); 
    pCObj = new Child(); 

    RemoveObj(&pPObj); 
    RemoveObj(&pCObj); // This is line 33 
    return 1; 
} 

但是编译器会发出错误:

classes.cpp:33: error: invalid conversion from ‘Child**’ to ‘Parent**’ 
classes.cpp:33: error: initializing argument 1 of ‘void RemoveObj(Parent**)’ 

回答

12

有洙许多方法来正确处理内存。

的一个接近你的例子是:

template <typename T> 
RemoveObj(T **p) 
{ 
    if (p == NULL) return; 
    delete *p; 
    *p = NULL; 
} 

另外,你可能想使用std :: auto_ptr的替代。它看起来像:

int main() 
{ 
    std::auto_ptr<Parent*> pPObj(new Parent); 
    std::auto_ptr<Child*> pCObj(new Child); 
    // no deletes needed anymore 
+0

关于第一个解决方案:什么是比较完善: 无效RemoveObj(无效** ppObj) – To1ne 2009-04-10 08:02:51

+0

第一个建议编译和作品。 void RemoveObj(void ** ppObj)可以被定义,但如果你尝试调用它,你的调用应该不会被编译。 – 2009-04-10 08:09:11

+0

@ To1ne:我认为删除void *实际上是未定义的。使用模板解决方案,您有一个正确的静态类型。应该为void *调用什么非平凡的析构函数? – 2009-04-10 08:09:21

1

您可以找到该书< C++常识>项目8指向指针的指针一些有用的信息。

2

你不需要为删除的包装,保持简单:

int main() 
{ 
    Parent* pPObj = NULL; 
    Child* pCObj = NULL; 
    pPObj = new Parent(); 
    pCObj = new Child(); 

    delete pPObj; 
    delete pCObj; // This is line 33 
    return 1; 
} 

记住你会遇到删除数组类型的对象有问题,你RemoveObj(因为你总是使用标delete)。另一种方法是通过一面旗子来表明你想要delete []。但正如我所说:KISS。

3

说得简单:

孩子是父母的一个子类,所以这意味着儿童*可与母公司*

儿童*被取代并非家长的一个子类*所以这意味着孩子**不能被父母代替**

“孩子”和“孩子*”不是相同的类型。

2

如果你的问题是处理内存和资源,最好的建议是完全忘记你的方法,并使用智能指针。 std :: auto_ptrboost :: shared_ptr将是一个起点。

如果你用智能指针保存所有的堆分配资源,你的代码将更加健壮。

3

你需要做的是取消所有指向你刚删除的对象的指针。指针的想法是将有多个指针存储同一对象的地址。如果没有,那么没有什么理由使用裸指针,所以你试图捕获的模式并不是很有用 - 但是你离第一个尝试这个模式的人很远。正如其他答案所提到的,处理指针的唯一方法是仔细控制对它们的访问。

你的问题的标题是绝对正确的!这有一个很好的理由。指针标识存储特定类型对象的位置。指向指针的指针可让您更改指针指向的对象。

void Foo(Parent **pp) 
{ 
    *pp = new OtherChild(); 
} 

Child类从Parent派生,所以做我的OtherChild类。假设编译器允许你这样做:

Child *c = 0; 
Foo(&c); 

您预期工作,但如果有,那么我们现在有一个Child指针c,其实指向的OtherChild一个实例。谁说这两种类型是兼容的?

同样,这是一个非常频繁的误解 - 它在其他语言中反复出现,尤其是关于C#中的List<Parent>List<Child>

0

可能是最简单的解决方案,我发现:

#define __REMOVE_OBJ(pObj) RemoveObj(pObj); pObj = NULL; 

并调用这一个:

__REMOVE_OBJ(pPObj); 
    __REMOVE_OBJ(pCObj); 

但我真的不喜欢现在的自己......

0

从讨论make shared_ptr not use delete

共享指针将确保您清理时你应该和你不能访问被破坏的东西。此外,您可以专注并提供备用销毁方法。

boost::shared_ptr<T> ptr(new T, std::mem_fun_ref(&T::deleteMe));