C++继承问题
Posted
技术标签:
【中文标题】C++继承问题【英文标题】:C++ inheritance problem 【发布时间】:2009-11-24 11:20:20 【问题描述】:这是我的课程:
父类,父对象
DerivedClass(继承自 ParentClass)、DerivedObj(继承自 ParentObj)。
ParentClass 有一个受保护的成员:
std::vector
DerivedClass 仅将 DerivedObj* 对象分配给该向量。
问题是:
当我使用 ParentClass 时,我想用类型的迭代器访问它的向量对象:
std::vector::const_iterator
当我使用 DerivedClass 时,我想用类型的迭代器访问它的向量对象:
std::vector::const_iterator
我怎样才能让它工作?
【问题讨论】:
您不应该在 STL 容器中使用指针元素,除非您 100% 确定没有人会修改它(例如使用 std::sort...)! STL 容器确实具有值语义,使用指针复制从来都不是一件好事! 我没有看到std::sort
的问题...我宁愿谈论 ::erase()
方法或类似的东西:/
@fmuecke:您必须将指针视为指针,正确处理所有权问题,并区分“复制”和“克隆”。 (或浅拷贝与深拷贝)。
【参考方案1】:
您可以在 DerivedClass
类中使用虚拟覆盖,返回 ParentClass
返回类型的子类型...
struct ParentClass
virtual ParentObj* get( const size_t index )
return m_objects[index];
;
struct DerivedClass : public ParentClass
virtual DerivedObj* get( const size_t index )
return dynamic_cast<DerivedObj*>( ParentClass::get(index) );
;
这两个函数都是相同的“vtable”条目,尽管它们的返回类型不同。
或者,您可以使用相同的技术来创建“继承的”迭代器。
除此之外,在DerivedClass
对象中包含DerivedObj*
的向量并不是一个坏主意,只要您保证它们也存在于ParentClass
的向量中。
【讨论】:
+1,提供 get() 方法看起来不错,并将强制转换限制为仅此函数。 如果类具有合适的不变量(例如,指针仅通过在 DerivedClass 中重写的虚拟成员函数添加到向量),您可以将其设为 static_cast。基本上是类型擦除。 是的,我知道。这听起来仍然不是一个好的代码实践(它出现在代码中的很多地方)。 @Jack,在重写的虚方法中返回原始返回类型的子类型称为协变返回类型。它本身并没有超载。【参考方案2】:我有一个问题:为什么DerivedClass
继承自ParentClass
?
您需要多态行为,还是要重用ParentClass
的实现?
继承经常被严重滥用。真的。
然后是(典型的)容器类问题,以及如何公开其元素。不幸的是,与它们应该模拟的指针不同,语言对迭代器的支持很差(尽管它们有很多东西)。
所以,提醒一下:继承是一种is-a关系,对于代码重用存在Composition。
在这里你可以完美地编写一个模板类来扮演容器的角色并提供通用的方法。
然后,对于阐述的问题...您可以编写自己的迭代器,具有正确的基派生关系,或者您可以选择预选一些算法(sort
、foreach
、erase_if
) 可以与用户提供的谓词一起使用。
template <class Value>
class Container
public:
template <class Pred>
void sort(Pred iPred);
template <class Pred>
Pred foreach(Pred iPred); // maybe a const-version ?
template <class Pred>
size_t erase_if(Pred iPred); // returns the number of erased
private:
std::vector<Value> m_data;
;
然后,开始上课:
class ParentClass
public:
virtual void foo() const;
private:
Container<ParentObj*> m_data;
;
class DerivedClass: public ParentClass
public:
virtual void foo() const;
private:
Container<DerivedObj*> m_data;
;
尝试将多态性与代码重用分开,问题应该会变得更简单。
【讨论】:
【参考方案3】:std::vector< ParentObj* >
和std::vector< DerivedObj* >
是两种完全不同的类型,因此您不能将一种隐式转换为另一种。您可以做的是使用dynamic_cast
将每个ParentObj*
转换为DerivedObj*
。但通常这不是一个好的做法。
【讨论】:
我知道,这就是我现在所做的...没有别的办法吗?我想过让 vector您不能使用基本的 C++ 继承来做到这一点。原因是当在DerivedClass
中使用时,编译器不知道向量只包含指向DerivedObj
的指针。我同意 Naveens 关于动态演员的声明。
您可以使用两个向量 std::vector< ParentObj* > mParent
和 std::vector< DerivedObj* > mDerived
以及一个虚拟的 Add()
函数。基本实现只会添加到mParent
。 DerivedClass
中的 Add
函数也将添加到 mDerived
。
ParentClass
将具有 GetParentIterator()
函数,DerivedClass
将具有另一个(附加)函数 GetDerivedIterator()
。
【讨论】:
【参考方案5】:你的继承设计错了。
DerivedClass
不能从 ParentClass
继承。
ParentClass
有一个受保护的成员 std::vector< ParentObj* >
。
并且DerivedClass
必须有另一个受保护的成员std::vector< DerivedObj* >
。
你可以创建模板类
template<class T>
struct MyClass
protected:
std::vector< T* > m_objects;
;
struct ParentClass : MyClass <ParentObj> ;
struct DerivedClass: MyClass <DerivedObj> ;
【讨论】:
它有什么变化?无论如何,为什么要使用受保护的成员,这超出了封装的目的... 这与 struct ParentClass std::vector以上是关于C++继承问题的主要内容,如果未能解决你的问题,请参考以下文章