Overriding a member variable in C ++

I ran into some difficult problem in some C ++ code, which is easiest to describe using code. I have classes that are something like this:

class MyVarBase { } class MyVar : public MyVarBase { int Foo(); } class MyBase { public: MyBase(MyVarBase* v) : m_var(v) {} virtual MyVarBase* GetVar() { return m_var; } private: MyVarBase* m_var; } 

I also have a subclass of MyBase, which must have a member of type MyVar, because it needs to call Foo. Moving the Foo function to MyVarBase is not an option. Does it make sense to do this:

 class MyClass : public MyBase { public: MyClass(MyVar* v) : MyBase(v), m_var(v) {} MyVar* GetVar() { return m_var; } private: MyVar* m_var; } 

This seems to work, but it looks very bad, and I'm not sure if this will cause a memory leak or break the copy constructor. My other options might be to name the MyVar variable in MyClass something else, but have it equal to the m_var pointer in the database or templatise MyBase in the MyVar type.

All of these options do not seem ideal, so I wanted to know if anyone else had a situation like this, and if there is a good way to make it work.

+6
c ++ oop
source share
3 answers

The right way to do this is to only have the variable in the base class. Since the derived class knows that it must be of the dynamic type MyVar , this is quite reasonable:

 class MyClass : public MyBase { public: MyClass(MyVar* v) : MyBase(v) {} MyVar* GetVar() { return static_cast<MyVar*>(MyBase::GetVar()); } } 

Since MyVar is derived from MyVarBase, the various GetVar types GetVar will work if GetVar was virtual (as in this case here). Please note that with this method, there should not be a function in MyBase that can reset point to something else, obviously.

Note that static_cast is the right choice in this case. Using dynamic_cast , as suggested by one commenter, tells GetVar readers and users that MyBase::GetVar() can return a pointer to an object, not a MyVar type. But this does not reflect our intention, since you only ever pass MyVar. Being consistent is the most important thing in software development. What you can do is say that it is not empty. At runtime, it will be aborted with an error message in the debug-builds of your project:

 MyVar* GetVar() { assert(dynamic_cast<MyVar*>(MyBase::GetVar()) != 0); return static_cast<MyVar*>(MyBase::GetVar()); } 
+13
source share

Without knowing more context, it’s hard to say for sure, but I would reconsider if you need this class hierarchy in the first place. Do you really need MyVarBase and MyBase classes? Could you leave with the composition instead of inheritance? You may not need a class hierarchy at all if you create templates for functions and classes that work with the above classes. Perhaps CRTP can help too. There are many alternatives to using virtual functions (and to some extent inheritance in general) in C ++.

In any case, your own proposed solution, of course, should not leak from memory (since it does not allocate any) and will not violate the default copy constructor either (because it just executes a member copy. Have an additional member in the derived class, but it also copied). Of course, you get the additional problem of synchronizing two variables, so I still don't like this solution.

Alternatively, you can remove the variable from the base class. Make the GetVar () function pure virtual, therefore it is implemented only in derived classes that can define a member variable in any way.

+2
source share

I think your mention of patterns might be a good option, so something like:

 class MyVarBase { }; class MyVar : public MyVarBase { int Foo(); }; template <class T> class MyBase { public: MyBase(T* v) : m_var(v) {} T* GetVar() { return m_var; } private: T* m_var; }; class MyClass : public MyBase<MyVar> { public: MyClass(MyVar* v) : MyBase(v) {} }; 

However, this will depend on which classes you can really change. In addition, the definition of β€œMyClass” may be redundant unless it has other members of the MyBase class and above.

0
source share

All Articles