简体   繁体   中英

C++ inheritance problem

Here are my classes:

ParentClass, ParentObj

DerivedClass (inherits from ParentClass), DerivedObj (inherits from ParentObj).

ParentClass has a protected member:

std::vector< ParentObj* >

DerivedClass allocates only DerivedObj* objects to this vector.

Problem is:

When I use ParentClass, I want to access its vector objects with an iterator of type:

std::vector< ParentObj* >::const_iterator

And when I use DerivedClass, I want to access its vector objects with an iterator of type:

std::vector< DerivedObj* >::const_iterator

How can I make it work?

You can use a virtual override in your DerivedClass class returning a subtype of the ParentClass return type...

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) );
    }
 };

Both functions are the same 'vtable' entry, though their return type differs.

Alternatively, you may use the same technique to create 'inherited' iterators.

Next to that, it's not a bad idea to have a vector of DerivedObj* 's in the DerivedClass object, as long as you guarantee that they are also present in the ParentClass 's vector.

I have a question there: Why does DerivedClass inherits from ParentClass ?

Do you need a polymorphic behavior, or do you want to reuse the implementation of ParentClass ?

Inheritance is often badly misused. Really.

Then there is the (typical) problem of having a container class, and how to expose its elements. Unfortunately the iterators are (despite all their goods) poorly supported by the language unlike the pointers they are supposed to emulate.

So, a reminder: Inheritance is a is-a relationship, for code reuse there is Composition .

Here you could perfectly write a template class that would play the part of the container and provide common methods.

Then, for the problem of exposition... you can write your own iterators, with the correct base-derived relationship, or you can opt to preselect a number of algorithms ( sort , foreach , erase_if ) that would work with user-supplied predicates.

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;
};

Then, on to your classes:

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;
};

Try to separate polymorphism from code reuse, and the problem should get simpler.

std::vector< ParentObj* > and std::vector< DerivedObj* > are two totally different types hence you can not implicitly convert one to another. What you can do is convert each ParentObj* to DerivedObj* using dynamic_cast . But generally it is not considered a good practice.

You can't do that using basic C++ inheritance. The reason is that the compiler doesn't know that the vector contains only pointers to DerivedObj when used in DerivedClass . I second Naveens statement about dynamic cast.

You could use two vectors std::vector< ParentObj* > mParent and std::vector< DerivedObj* > mDerived and a virtual Add() function. The base implementation would add only to mParent . The Add function in DerivedClass would also add to mDerived .

ParentClass would have a GetParentIterator() function and DerivedClass would have another (additional) function GetDerivedIterator() .

Your inheritance design is wrong.

DerivedClass must not inherit from ParentClass . ParentClass has a protected member std::vector< ParentObj* > . And DerivedClass must have another protected member std::vector< DerivedObj* > .

You may create template class

template<class T>
struct MyClass {
  protected:
    std::vector< T* > m_objects;
};

struct ParentClass : MyClass <ParentObj> {};
struct DerivedClass: MyClass <DerivedObj> {};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM