I'm having this kind of code:
class Ref {<undefined>};
Ref refObjectForA, refObjectForB;
class Base
{
public:
Base(const Ref & iRef) : _ref(iRef) {}
virtual ~Base() {}
const Ref & ref;
};
class A: public Base
{
public:
A() : Base(refObjectForA) {}
virtual ~A() {}
};
class B: public A
{
public:
B() : Base(refObjectForB) {} // won't compile: Base is not direct base of B
virtual ~B() {}
};
As the attribute is a reference, I think I can only set it in constructor, so I need to call Base constructor in B().
I've found two ways: providing a "forward" constructor in A (but this implies adding code in all classes that might be inherited):
A(const Ref& iRef): Base(iRef)
or using virtual inheritance:
class A: public virtual Base
Second option allows more straightforward code in B implementation but I'm wondering if I'm misusing virtual inheritance in an ugly trick or if it is a valid usecase.
Can I use virtual inheritance in this case?
If no, for what reason?
One of the "unexpected" behaviors I've found is that it's not possible to static_cast a Base pointer to a B pointer because of the virtual inheritance.
Moreover I'm also wondering why it works (I mean why a B().ref == refObjectForB): I would think that the implicit call to default A() constructor in B() would overwrite the ref attribute after explicit Base constructor, but maybe it's not true with virtual inheritance.
The best option I can see if you want to stick to your inheritance hierarchy is to implement protected constructors taking a reference which they'll forward to the Base class. Making a constructor protected makes sure that a (final) instance can't be constructed using this constructor, so it will only be used in subclasses to initialize the super classes.
With some more or less ugly and dangerous macro, this becomes easy to be written:
#define REF_FORWARD_CTOR(ClassName, DirectSuperClassName) \
protected: ClassName(class Ref &r) : DirectSuperClassName(r) {} \
public:
class A : public Base
{
REF_FORWARD_CTOR(A, Base)
public:
A() : Base(refObjectForA) {} // normal ctor
};
class B : public A
{
REF_FORWARD_CTOR(B, A)
public:
B() : A(refObjectForB) {} // normal ctor
};
An alternative design would be to let A and B both derive (directly) from Base. Then, add functionalities by using multiple inheritance and "common classes", maybe private, depending on what they are for:
class Base {
};
class Common {
// common stuff used by both A and B
};
class A : public Base, public Common {
// no further stuff here
};
class B : public Base, public Common {
// add more stuff, or put it in a common super-class again,
// if some classes want to inherit from B again
};
The problem with this design is that functionality in Common can't access the stuff in A and B. To solve this, do one of the following:
If only static stuff is required: Use CRTP to specify A / B in a concrete Common type: Common<A> can then use A::..., but doesn't have anything to do with a concrete instance of A
If an instance is required: provide a pointer / reference in the constructor of Common (slight overhead)
Putting the first two solutions together: Use CRTP, implement wrapper functions in A and B which call functions in Common<A> and Common<B> providing this (which is a A* or B* via an extra parameter.
Same as above, but the class Common can also be non-templated (no CRTP) if you overload / template these functions on this pointer argument ("CRTP on functions", if you want to call it like that). Code speaks louder than words. (Example code is without your references and focuses on the "common class".)
Yes you can technically use virtual inheritance to achieve the goal of providing the reference in the most derived class.
And yes, that's a design smell.
Your classes should not need to be aware of anything but their immediate bases (virtual inheritance is the exception to the rule, when it's needed for other reasons).
Sticking to the proposed classes hierarchy, in order to solve the problem it is enough to use the "using-declaration" to bring the Base's constructor to the protected part of the class A, i.e.:
class A: public Base
{
public:
A() : Base(refObjectForA) {}
virtual ~A() {}
protected:
using Base::Base;
};
Related
The Diamond Problem and Virtual Inheritance are topics that have been discussed endlessly, though while researching them I found myself still uncertain of a few specifics when it comes to calling Base constructors due to the large variety of ways the same terminology was used in different places.
I understood that in the typical Diamond inheritance setup it is the responsibility of the most derived, concrete class to explicitly call the constructor of the base class that is virtually inherited from, lest a default constructor be called (if available); however, I wanted to know exactly what this meant for the constructors of the "middle" classes in the case where the base class does not/cannot have a default constructor.
I did a basic test of this case and would like to confirm that I now correctly understand my findings, just to make sure there are no gotchyas or misconceptions I have.
Note the following code is cutdown to just focus on constructor calls and doesn't demonstrate why I need a diamond inheritance tree in the first place.
class Base
{
private:
std::string mString;
protected:
Base(std::string str) : mString(str) {}
public:
void identify() { std::cout << mString << std::endl; }
};
class DerivedA : public virtual Base
{
public:
DerivedA(std::string str) : Base(str) {}
};
class DerivedB : public virtual Base
{
public:
DerivedB(std::string str) : Base(str) {}
};
class Concrete : public DerivedA, public DerivedB
{
public:
Concrete(std::string str) :
Base(str),
DerivedA("not used"),
DerivedB("not used")
{}
};
int main(int argc, char *argv[])
{
Concrete con("I am concrete");
DerivedA derA("I am DerivedA");
DerivedB derB("I am DerivedB");
con.identify();
derA.identify();
derB.identify();
}
// Output:
// I am concrete
// I am DerivedA
// I am DerivedB
So am I correct in that what happens here is that although I have to call the Base constructor in both Derived classes because there is no default constructor, when Concrete is being constructed the instance of Base is created first via the call to its constructor in Concrete's initialization list, followed by the creation of Derived A and then Derived B; however, in their constructors the call of Base's constructor is ignored, and instead the instance of Base they need that would have resulted from that call is instead provided via a reference to the instance spawned from Concrete's initialization list?
Based on the output, it seems that due to the virtual inheritance the calls to Base's constructor within DerivedA/B's initialization list are only actually used if I instantiate a copy of them directly (which I may actually want to do at times, so this is indeed useful), otherwise the calls to the Base constructor in the most derived class essentially "override" the same constructor calls in the classes higher up the inheritance tree.
Do I understand this correctly?
I have a base class:
class Base {
protected:
int m_a;
virtual void foo() = 0;
}
And a derived class(es)
class Derived : public Base {
public:
Derived(int a);
}
The base class is abstract, so only derived classes can be created.
How is the better way to implement the derived Ctor?
Derived::Derived(int a) : Base(a) {}
Base::Base(int a) : m_a(a) {}
Or
Derived::Derived(int a) { m_a = a;}
Base::Base(){}
Is it better to remove the member from Base constructor, since it cannot be created alone, OR to keep it on the Base constructor to stay the assignment for him?
Your first solution- giving the base class an explicit constructor - is preferable as general pattern:
it avoids other classes inherited from Base forgetting to initialize m_a. Instead, the signature of the class indicates initialization is required.
if multiple classes inherit from base, and initialization is more complex (e.g. a range check) , this code - and policy - is not distributed over multiple derived classes
if m_a is immutable, constructor initialization is required
derived classes might have more than one CTor, more places to forget
Only downside: a little more typing - as long as you don't count the additional "I'm a little lazy today so don't forget to init m_a in all derived classes constructors"
The "signature announces the requirements" is IMO sufficient to make this the default pattern, so is "the other way requires making m_a protected", as mentioned in the comments.
I would prefer :
Derived::Derived(int a) : Base(a) {}
Base::Base(int a) : m_a(a) {}
By this way you make your code more encapsulated and Base members took care about its init list, there can be some more init logic in base class constructor depending on m_a instead of just initing m_a. In this case you pass initial value to your base constructor and then derived class in his constructor has initialized constructor of base class.
You should try to pass init values to your Base class, imagine you have 5 Derived classes and you need to init base class at all of yours derived ctors.
Can you inherit the same class twice? E.g. :
class Base {
};
class Foo : public Base {
};
class Bar : public Base {
};
class Baz : public Foo, public Bar {
//is this legal?
// are there restrictions on Base
// (e.g. only virtual methods or a virtual base)?
};
Yes it is legal, and no there are no restrictions on Base.
You should however be aware that this causes two different objects of type Base to exist within Baz, which will require you to use qualified names to tell C++ which version of Base you mean, when you try to access its members.
C++ provides a mechanism called virtual inheritance to solve this problem (if it is a problem for you):
class Base { };
class Foo : public virtual Base { };
class Bar : public virtual Base { };
class Baz : public Foo, public Bar { };
This will share the Base object between the Foo and Bar objects within Baz
C++ does support multiple inheritance.
The syntax for class Baz is correct.
See this tutorial for some caveats and more information: http://www.cprogramming.com/tutorial/multiple_inheritance.html
Yes, it's legal to inherit the same class twice.
If the inheritance is non-virtual, as in your example (I just fixed the syntax and formatting),
class Base {};
class Foo : public Base {};
class Bar : public Base {};
class Baz : public Foo, public Bar {};
then it's generally necessary to qualify any use of something from such duplicate base.
If however each direct inheritance of the common base is virtual (using the keyword virtual), then there is only one common sub-object of the common base. This is the so called diamond pattern of inheritance in C++. It's a bit tricky, e.g. in that it yields at least one sub-object spread over a non-contiguous region of memory, and in that it's the most derived class that is responsible for initializing the common virtual base. Also it introduces some inefficiency and is associated with some compiler bugs. So it's seldom used, but sometimes it's necessary – e.g., it can emulate Java interface inheritance, and it can be used to emulate Java final (not necessary in C++11).
Yes, it is legal, but having two subobjects of the same Base class causes many difficulties, because you always must explicitly say which one you want, using the scope operator ::.
Baz x;
Base& y = x; // Illegal because ambiguous.
Base& y = (Bar&)x; // Now unambiguous.
Part of that trouble can be solved by inheriting Base using virtual inheritance, which makes sure only exactly one Base.subobject exists.
In that case, the virtual base is always initialised by the most derived constructor, before all non-virtual bases.
class Base {}
class Foo : public virtual Base {}
class Bar : public virtual Base {}
class Baz : public Foo, public Bar {}
Baz x;
Base& y = x; // Legal, because even though both direct bases inherit from `Base`,
// they do so virtually, thus there is only one Base subobject
Base& y = (Bar&)x; // Still unambiguous.
Now, if Foo used protected or private inheritance, you could not cast down to Foo::Derived in Baz or completely outside in the first (non-virtual) example.
In the virtual example, you could, because that sub-object is also reachable using Bar, and the most accessible path determines the access rights.
This is legal.
But restrictions arise when classes are labeled protected and private classes before it. For this, its respective functions and attributes are protected and private.
I have two classes in a class hierarchy where a parent class needs to have an instance of a class derived from it as a member variable. As an example:
class B;
class A {
public:
B* binst;
A();
};
class B : public A {
};
A::A() {
binst = new B;
}
Obviously, this causes an infinite recursion in the constructors, because to create a new B you have to call A's constructor, which creates a new B which calls A's constructor, and so ad infinitum.
Is there a way around this? The problem I'm having in this is that A has to have a B in it, but B must be derived from A, and there's not a way to prevent that.
To get an idea of why I need to do this, consider an object oriented hierarchy for a scripting language (like python or ruby or lua, etc):
All instances of anything are derived from a base class, Object.
Object has a method lookup table, which is an instance of MethodTable.
MethodTable is derived from Object, and must be, for the scripting language to be able to operate on it.
"Object has a method lookup table"
"MethodTable is derived from Object"
Putting aside coding concerns, do these statements really make sense together from even a conceptual standpoint? Should a MethodTable have its own MethodTable which then has its own MethodTable... etc?
I'd say it sounds like you need to refactor your concepts a bit. For instance, perhaps Object itself should somehow be responsible for exposing the necessary pieces of its MethodTable member. Thus not requiring MethodTable itself to be an Object. (There may be various other feasible designs too. It's hard to say without deeper knowledge of the actual project.)
Edit: Typically, compiler/implementation-internal types don't derive from language-dependent types. If you look at the internals of Java, their inheritance implementation won't derive from Object. Object is a language construction, it's part of your language's interface. A method table is part of the implementation. A method table should not be operated on by the language, it should be operated on by the implementation.
Moreover, enforced deriving from Object is a stupid thing to do and it happens because you didn't consider the language design and how the users were going to write generic code properly. This is especially true in dynamically typed languages like Lua or Python.
Object could have a private MethodTableImpl member and a public getter that returns a MethodTable. MethodTable contains a MethodTableImpl and derives from Object.
I don't know the purpose of your classes but here is a suggestion :
class A
{
public:
virtual void func DoIt () = 0;
...
};
class B : public virtual A
{
public:
};
class C : public virtual A ,B
{
void func DoIt () { /* statements */ }
};
now there is only 1 instance of class A.
It would be helpful to understand exactly are you trying to achieve via this construct.
As you've noted yourself, this is effectively like having A's constructor construct an instance of A, and that's an unavoidable path to stack overflow.
A more general solution would be to provide a set_subclass method for a pointer to an instance of A, which could then be populated by any subclass of A, not just B.
class A {
public:
A();
virtual ~A();
set_subclass(A* sub) { subclass = sub; }
private:
A* subclass;
};
// List(1) or Stream(2) using inheritance
struct B;
struct A {
B *inst;
A(B *inst_) : inst(inst_) {}
A() : inst(0) {}
};
struct B : A {
B(B *_inst) : A(inst) {}
// chose option 1 or 2
B() : A() {} // option 1: List
B() : A(0) {} // same as above
B() : A(this) {} // option 2: Stream
};
auto B3 = new B(new B( new B));
// This is either a length 3 list (1)
// or a stream (2) implemented by self ref 3rd element
You can make a constructor for class A which accepts a pointer to an object to class B and assign this pointer instead of allocating a new B:
A::A(B* b) : binst (b) {}
And in the construct of class B you pass 'this' in constructor of A:
B::B() : A(this) {}
The compiler will probably complain about it, but you can try. (It is ugly, though.)
Note that you can NOT use the binst pointer to access object B in A's constructor, because it's not fully constructed yet.
Does it actually need the binst as a member, or does it simply need to access it?
class B;
class A {
public:
B& binst(); //throws exception if not derived from B
A() {}
virtual ~A() {} //effectively required for the dynamic_cast
void foo();
};
class B : public A {
public:
void bar() {};
};
B& A::binst() {return dynamic_cast<B&>(this);}
void A::foo() {return binst().bar();}
Recently one of my friend asked me how to prevent class inheritance in C++. He wanted the compilation to fail.
I was thinking about it and found 3 answers. Not sure which is the best one.
1) Private Constructor(s)
class CBase
{
public:
static CBase* CreateInstance()
{
CBase* b1 = new CBase();
return b1;
}
private:
CBase() { }
CBase(CBase3) { }
CBase& operator=(CBase&) { }
};
2) Using CSealed base class, private ctor & virtual inheritance
class CSealed
{
private:
CSealed() {
}
friend class CBase;
};
class CBase : virtual CSealed
{
public:
CBase() {
}
};
3) Using a CSealed base class, protected ctor & virtual inheritance
class CSealed
{
protected:
CSealed() {
}
};
class CBase : virtual CSealed
{
public:
CBase() {
}
};
All the above methods make sure that CBase class cannot be inherited further.
My Question is:
Which is the best method ? Any other methods available ?
Method 2 & 3 will not work unless the CSealed class is inherited virutally. Why is that ? Does it have anything to do with vdisp ptr ??
PS:
The above program was compiled in MS C++ compiler (Visual Studio).
reference : http://www.codeguru.com/forum/archive/index.php/t-321146.html
As of C++11, you can add the final keyword to your class, eg
class CBase final
{
...
The main reason I can see for wanting to do this (and the reason I came looking for this question) is to mark a class as non subclassable so you can safely use a non-virtual destructor and avoid a vtable altogether.
You can't prevent inheritance (before C++11's final keyword) - you can only prevent instantiation of inherited classes. In other words, there is no way of preventing:
class A { ... };
class B : public A { ... };
The best you can do is prevent objects of type B from being instantiated. That being the case, I suggest you take kts's advice and document the fact that A (or whatever) is not intended to be used for inheritance, give it a non-virtual destructor, and no other virtual functions, and leave it at that.
You are going through contortions to prevent further subclassing. Why? Document the fact that the class isn't extensible and make the dtor non-virtual. In the spirit of c, if someone really wants to ignore the way you intended this to be used why stop them? (I never saw the point of final classes/methods in java either).
//Note: this class is not designed to be extended. (Hence the non-virtual dtor)
struct DontExtened
{
DontExtened();
/*NOT VIRTUAL*/
~DontExtened();
...
};
1) is a matter of taste. If I see it correctly, your more fancy 2nd and 3rd solutions move the error in certain circumstances from link time to compile time, which in general should be better.
2) Virtual inheritance is needed to force the responsibility to initialize the (virtual) base class to the most derived class from where the base class ctor is no longer reachable.
To answer your question, you can't inherit from CBase because in virtual inheritance a derived class would need to have direct access to the class from which it was inherited virtually. In this case, a class that would derive from CBase would need to have direct access to CSealed which it can't since the constructor is private.
Though I don't see the usefulness of it all (ie: stopping inheritance) you can generalize using templates (I don't think it compiles on all compilers but it does with MSVC)
template<class T>
class CSealed
{
friend T; // Don't do friend class T because it won't compile
CSealed() {}
};
class CBase : private virtual CSealed<CBase>
{
};
If you can, I'd go for the first option (private constructor). The reason is that pretty much any experienced C++ programmer will see that at a glance and be able to recognize that you are trying to prevent subclassing.
There might be other more tricky methods to prevent subclassing, but in this case the simpler the better.
From C++11 onward, there is a clean solution that I am surprise not to see here. We can make the class final preventing any further inheritance.
class Foo final {};
class Bar: public Foo {}; // Fails to compile as Foo is marked as final
class myclass;
class my_lock {
friend class myclass;
private:
my_lock() {}
my_lock(const my_lock&) {}
};
class myclass : public virtual my_lock {
// ...
public:
myclass();
myclass(char*);
// ...
};
myclass m;
class Der : public myclass { };
Der dd; // error Der::dd() cannot access
// my_lock::my_lock(): private member
I found it here to give credit. I am posting here just other people can easily access
http://www.devx.com/tips/Tip/38482
To elaborate on Francis' answer: if class Bottom derives from class Middle, which virtually inherits from class Top, it is that most derived class (Bottom) that is responsible for constructing the virtually inherited base class (Top). Otherwise, in the multiple-inheritance/diamond-of-death scenario (where virtual inheritance is classically used), the compiler wouldn't know which of the two "middle" classes should construct the single base class. The Middle's constructor's call to the Top's constructor is therefore ignored when Middle is being constructed from Bottom:
class Top {
public:
Top() {}
}
class Middle: virtual public Top {
public:
Middle(): Top() {} // Top() is ignored if Middle constructed through Bottom()
}
class Bottom: public Middle {
public:
Bottom(): Middle(), Top() {}
}
So, in the the approach 2) or 3) in your question, Bottom() can't call Top() because it's inherited privately (by default, like in your code, but it's worth making it explicit) in Middle and thus is not visible in Bottom. (source)