I tried splitting a data structure into several base classes to reuse the code and data members.
There i encountered the issue that it would greatly simplify my code if i could initialize the members of one base class with the members of another.
struct Base1
{
const int a;
Base1() : a(3) {}
};
struct Base2
{
const int b;
Base2() : b(a*2) {}
};
struct Derived :
Base1,
Base2
{
Derived() : Base1(), Base2() {}
};
Since the above is not possible, I'm searching for a way to achieve something similar, with changing the class Base1 and Base2 as little as possible.
How could I do that?
You'll need a clean interface. As Base2 is not related to Base1 in any way per your example, the dependency you describe shall be part of it's interface to the outward world. It is not an implementation detail.
As such the correct solution would be to provide an explicit (i don't mean the keyword) constructor:
Base2(int a) : b(a*2) {}
For Derived you then get:
Derived() : Base1(), Base2(a) {}
Notice that Base1 gets initialized before Base2 and as such a is already available.
Related
I have an issue with the following class structure,
class Base { int a; };
class Derived : public Base { int b; };
class OtherBase { Base c; };
class OtherDerived : public OtherBase { Derived d; };
The issue is that OtherDerived stores two instances of Base, one through the
inheritance to OtherBase and one from the inheritance to Base of the data
member d. I would like OtherDerived to store only one instance of Base.
What are the possible to achieve that while minimizing code duplication ?
One possible solution would be to use multiple inheritance:
class Base { int a; };
class Derived : public virtual Base { int b; };
class OtherBase : public virtual Base {};
class OtherDerived : public OtherBase, public Derived {};
However, here, it might not make sense for OtherBase to inherit from Base,
we might not want to present the Base interface to the user through
OtherBase.
A way to solve the issue would be to use private inheritance:
class Base { int a; };
class Derived : public virtual Base { int b; };
class OtherBase : private virtual Base {};
class OtherDerived : public OtherBase, private Derived {};
In this case, I'm wondering if it is good practice to use inheritance as a
substitute for a data member. I have been taught that inheritance of Derived
on Base should be present when “a Derived is also a Base”. In the
suggested data structure, OtherBase might not be a Base. Is my undestanding
of good practices concerning inheritance wrong or outdated ?
PS: I'm open to suggestion for an easier to read question's title.
If OtherDerived needs a Derived member, but not its Base part then there is something wrong with your design. It means that Derived is doing more than it should. Either it needs to have Base as base to be fully functional or not. It cannot be both. Use this instead:
class Base { int a; };
class Foo { int b;}
class OtherBase { Base c; };
class OtherDerived : public OtherBase { Foo d; };
And If you actually do need the original Derived elsewhere, it can be
class Derived : public Base, Foo {};
Following explanation and examples from here I have exemplary constructed the following inheritance model creating a diamond
class Base {
public:
int data_;
Base(int d) : data_(d) {}
Base() = deleted;
};
class A : public virtual Base {
public:
A() : Base(42) {};
};
class B : public virtual Base {
public:
B() : Base(24) {};
}
class AB : public A, public B {
public:
AB() : Base(-1) {};
}
so far so good; note, that AB() needs to call to the Base(int)-ctor now. This is kind of understandable, because having the alternative initializer branches of going through AB>>A>>Base or AB>>B>>Base would not result in a well defined behavior at that.
Lets branch out from class A into a side-branch before we even have closed the diamond:
class A_Child : public A {
public:
A_Child() : A() {}; // not permitted by compiler
}
This will not compile, as the compiler will explicitly ask for to specify the ctor Base(int) in the inializer list of A_Child.
I don't quite understand this behavior; as we are no longer virtually inheriting at this point and the path of initalization of A_Child>>A>>Base is not ambiguous.
It seems now for every furthermore derived class of A_Child I have to again specify the Base(int) initializer explicitly. This is kind of breaking the encapsulation as every code that derives from this class needs to know how the class at the very base acts and is implemented.
Is there any way to stop or to break the virtual inheritance once I branch into a side-line?
Problem
I am looking for the best way to define the variables in parent-child classes, in order to be called by a pointer to their parent class.
This is the protocode:
class Base {
public:
virtual void function() = 0;
};
class A : public Base {
public:
int a, b;
A(int a_, int b_) : a(a_), b(b_) {};
void function() { // do something.. }
};
class B : public Base {
public:
int a, b;
B(int a_, int b_) : a(a_), b(b_) {};
void function() { // do something.. }
};
Base* elements[2] = {
new A(1,2),
new B(3,4)
};
Since I define a, b in both constructors, I might define them in the abstract class Base. This way the code should be more efficient and clean. Is this practice correct? How should I define them?
Possible solutions
The solution I have in mind is implementing a function that returns for example a like this:
class Base {
public:
virtual int return_a() = 0;
};
class A : public Base {
public:
int a, b;
A(int a_, int b_) : a(a_), b(b_) {};
int return_a() {
return a;
}
};
int main(){
int a = elements[0]->return_a();
}
This works, but I am sure it is not an efficient way. Is it better to define a, b in the abstract class? Thanks
Is this practice correct?
I think this is turning into an opinion-based question-answer. If all your derived classes must include the members a and b, then in my opinion, they should be part of the base class. This way, you are guaranteed that all your derived classes will include the members a and b and you (or someone else) won't run the risk of forgetting to include them. Furthermore, by including the members in the base class, you save memory by not having to include them at every single derived class. C++'s virtual provides you with all the necessary tools to accomplish polymorphism, which is what happens when you create an array of Base *.
I would also recommend you use the keyword override for the virtual functions that are overridden in the derived class, and the keyword final for the derived classes that are not meant to become base classes. You can read the benefits of using those keywords from Scott Meyers Modern C++ book.
struct Base
{
int a, b;
Base(int a_, int b_) : a(a_) , b(b_)
{;}
virtual void function() = 0;
};
struct A : Base // A can be a base class of another class.
{
A(int a_, int b_) : Base(a_,b_)
{;}
void funtion() // this will compile, but it's not going to override the Base::function()
{;}
};
struct B final : Base // B can never become a base class.
{
B(int a_, int b_) : Base(a_,b_)
{;}
void funtion() override // this won't compile because override will see that we mis-spelled function()
{;}
};
However, there is no C++ rule that prohibits you from including the members in all of your derived classes.
Also, if all your members are public, then you can use a struct to avoid having to type public inside the classes and in the inheritance method.
struct Base
{
// all members are public
};
struct Derived : Base // public inheritance by default.
{
// all members are public
};
This is somewhat opinion based, but here is what I think based on the code you have posted.
Since you have made Base (from which all classes are derived) an abstract class, it appears that you want to use it as an interface.
In that case, it is better to distinguish between interface inheritance and implementation inheritance. Let Base not have any data which means that it would not require any constructors.
This is one of the coding guidelines given by Bjarne Stroustrup titled: When designing a class hierarchy, distinguish between implementation inheritance and interface inheritance.
The reason given is:
Implementation details in an interface make the interface brittle; that is, make its users vulnerable to having to recompile after changes in the implementation. Data in a base class increases the complexity of implementing the base and can lead to replication of code.
Note that you do not need getters or setters if the data in derived classes is public.
Consider this example of code:
class Base
{
public:
Base() {}
};
class Derived1 : public Base
{
public:
Derived1() : Base() {}
};
class Derived2 : public Base
{
public:
Derived2() : Base() {}
};
Is there any to make that Derived1 has-a Derived2 and Derived2 has-a Derived1?
The best solution would be by using a third class which has those two objects. But in case high performance is needed?
An example might be a two-way client-server application.
EDIT: Consider that that's just a summary example. In the real code each of the three classes could throw an exception; I made sure that the code is exception-safe, though.
You can accomplish a "has-a" relationship with a forward declaration which basically tells "this class exists, it's just not declared yet"
#include <iostream>
using namespace std;
class Base
{
public:
Base() {}
};
// Forward declaration
class Derived1;
class Derived2 : public Base
{
friend class Derived1;
public:
Derived2() : Base() {}
private:
Derived1 *ptr;
};
class Derived1 : public Base
{
public:
Derived1(Derived2& obj) : Base(), ptr(&obj) {
obj.ptr = this;
}
private:
Derived2 *ptr;
};
int main() {
Derived2 obj2;
Derived1 obj1(obj2);
return 0;
}
http://ideone.com/RVU8AR
This way the two classes can communicate with each other. Notice the private pointers and the initialization into the constructor. With the "friend" declaration one class is able to modify the other class's private members.
Each class can hold a pointer:?
class Derived1
Derived2 *p_d2;
class Derived2
Derived1 *p_d1;
I have a quite special situation in my C++ program.
Look at the following class setup:
class Base1 {
public: void baseMethod();
}
class Base2 : public Base1 {
...
}
class Common {
public: void commonMethod();
}
class Derived1 : public Base1, public Common {
...
}
class Derived2 : public Base2, public Common {
...
}
Base1 and Base2 are unchangeable for me as they are part of a library.
What I want to achieve is that both Derived1 and Derived2 share the same method commonMethod(), so I use class Common with that method as a common base for Derived1 and Derived2.
The problem now is that commonMethod() shall contain a call to baseMethod() which is defined in Base1! In the context of a Derived1- or Derived2-object this is legal, but how to define that method in Common?
I know that if I would declare Base2 as virtual derived class from Base1 and the same for Common, it shouldn't be a problem (at least for Derived2, not sure about Derived1). But as I can't modify Base2 that's not possible anyway.
Also letting Common inherit from Base2 and then Derived1 and Derived2 solely from Common doesn't work because I don't want Derived1 to inherit from Base2!
What then came to my mind was to make a dynamic_cast within commonMethod():
void Common::commonMethod() {
...
Base1* self = dynamic_cast<Base1*>(this);
if(self) {
self->baseMethod();
}
...
}
This seems to work, but I'm not sure if this is a "nice" solution...
Do you have any ideas how to make it better? Or do you think this solution isn't bad at all? :)
If the only purpose of Common is to provide a common implementation of that one method, you can use the CRTP pattern and template it on the type of the base. At this point you could decide whether it makes sense to keep it as multiple bases of the DerivedX types or it could make sense to linearize the inheritance hierarchy:
// Option1
template <typename Derived>
struct Common {
void commonFunction() { ... static_cast<Derived*>(this)->foo(); ... }
};
struct Derived1 : Base1, Common<Derived1>
// Option2 (not strictly CRTP, but close)
template <typename Base>
struct Common : Base {
void commonFunction() { ... this->foo(); ... } // keep the this-> here
};
struct Derived1 : Common<Base1>
If I were you, I'd choose composition over multiple inheritance, i.e. to define common as a member object of derived classes.
class Base1 {
public: void baseMethod();
}
class Base2 : public Base1 {}
class Common {
public:
Common(Base1 *base): m_base(base) {}
void Common::commonMethod()
{
m_base->baseMethod();
}
private:
Base1 *m_base;
}
class Derived1 : public Base1
{
public:
Derived2(): m_common(this) {}
private:
Common m_common;
}
class Derived2 : public Base2
{
public:
Derived2(): m_common(this) {}
private:
Common m_common;
}
There is a potential risk of going this way though. Since member object(Common) is constructed first before the outer object(Derived1 or Derived2), you want to make sure no methods from the Derivedx object is called in Common's constructor.