c++ base class contain instance of a derived class - c++

I was wondering if someone could explain to me how I might be able to implement something similar to this:
namespace advanced_cpp_oop
{
class A
{
B b;
};
class B : public A
{
};
}
int main()
{
}
Where an instance of a base class can contain an instance of a derived class? When the above code is compiled the following error is generated:
g++ advanced_cpp_oop.cpp
advanced_cpp_oop.cpp:8:5: error: ‘B’ does not name a type
The (almost) equivalent Java code which does compile is:
public class AdvancedCppOop
{
public static void main(String[] args)
{
A a;
}
}
class A
{
B b;
}
class B extends A
{
}
Thanks

You need to add a pointer and a forward declaration:
namespace advanced_cpp_oop
{
class B;
class A
{
B* b;
};
class B : public A
{
};
}
In your C++ code, you are creating an instance of your class B inside class A, which is not possible since the compiler does not yet know anything (especially not the size) of class B.
With the code from my answer, you need to dynamically allocate an instance of class B and assign it to the b pointer somewhere else in your code.
On a side note, from design perspective, this does not really make sense since a parent class should not depend on a sub class.

You have to do it with some type of pointer, such as unique_ptr, and a forward declaration:
class B;
class A
{
std::unique_ptr<B> b;
};
class B : public A
{
};
This is silly though and you should probably rethink your design.

There is one very important difference between C++ and Java. C++ is a language with value semantics, while Java is a language with reference semantics. When in Java you create a variable of anything other than a primitive type, you are not creating an object of that type, but a reference to such an object. On the contrary, in C++ the same construct refers to an actual object.
If you keep this in mind, it is simple to understand why the following cannot possibly work:
class Base {
Derived d;
};
class Derived : Base {};
The first definition in C++ means that the object Base contains internally (not by reference) an object of type Derived. At the same time, Derived contains by means of inheritance a subobject of type Base.
That means that Derived contains a Base that contains a Derived containing a Base...
What would be the size of Base or Derived?
In a language with reference semantics, or in C++ if you use pointers, that is not a problem. The Base object contains a reference/pointer to Derived. Derived contains a Base subobject by means of inheritance. The size of Base is well known: all the other fields plus the size of a reference/pointer. The size of Derived is whatever the size of Base is plus any extra members that are added.

Andreas beat me to the correct answer, but I'll just add that the Java code works only because Java objects are implicitly held by pointers (hence the B b = new B(...); statements sprinkled throughout Java code) even if it doesn't look like it. Your original C++ code doesn't work (even with a forward declaration of class B added) because the compiler doesn't know how big a B object is, and thus doesn't know how big an A object that contains it will be. On the other hand, all pointers have the same size (regardless of pointed-to type), so the compiler has no such problems when you replace a B object with a pointer to a B object in class A.

Related

Is there a way to dynamically change an object to another type?

Let's say I have a class A that inherits from its parent class B, and there is another class C that also inherits from class B. Is there a way to change this pointer of class A to class C at run time?
class A : public B {
A::someFunction() {
//can I change this pointer to class C here?
}
}
class C : public B {
...
}
You cant and you shouldn't. The reason is pretty simple. Take a look at this code,
class Base {
public:
Base() {}
virtual void SayHello() {}
};
class A_Derived : public Base {
public:
A_Derived() {}
virtual void SayHello() override { ... }
void SayAllo() { ... }
};
class B_Derived : public Base {
public:
B_Derived() {}
virtual void SayHello() override { ... }
void SayBello() { ... }
};
Now when is we assign the A_Derived class pointer to B_Derived, the compiler will allow to call the SayBello method. This is because for the compiler, its a B_Derived class pointer, it doesn't know about the actual pointer data is pointing at a data block of A_Derived (because inheritance is not compile time, its runtime). So what happens when you call SayBello using that pointer? Its gonna be undefined behavior. You see the issue?
This is why you cant do it (logically and also using C++ style casting).
Is there a way to dynamically change an object to another type?
No. The type of an object cannot change through its lifetime.
Let's say I have a class A that inherits from its parent class B, and there is another class C that also inherits from class B. Is there a way to change this pointer of class A to class C at run time?
No.
At best, you could destroy the original object, and reuse its memory to create another object. Obviously the size and alignment of the memory must be sufficient for the new type. Any reference (which includes pointers such as this in a member function) to the old object will have been invalidated by the destruction of the original object. Reuse of storage is an advanced topic which I don't recommend to beginners.
There is no valid way to do this for one simple reason - in your class inheritance structure, an object of class A cannot be also an object of class C. In C++, two objects of different types can have the same address if and only if one of the objects is a subobject of the other, which is not your case. If you cast a pointer to A to a pointer to C, the pointer will still refer to an object of type A, and dereferencing the casted pointer would result in undefined behavior.
Most probably, what you want to do is to create an object of class C from an object of class A. You can use a converting constructor or a conversion operator to implement this.
Note that if what you really want is to reuse the storage allocated for the object of type A, you will still need to destroy the object A first and then construct the object C. You will have to save any relevant data from A before destroying it to be able to construct C with the data.

Does the code get copied to derived class?

Whenever I derive a new class from base class say:
#include <iostream>
class A {
protected:
int f;
public:
void get() {
std::cout << "The address is: "
<< &f << std::endl;
}
};
class B : public A {
// ....
};
int main() {
A a;
a.get();
B b;
b.get();
return 0;
}
The address is: 0xbfb0d5b8
The address is: 0xbfb0d5bc
Does this means that all the code from class A will be copied to class B? Since I have nothing in class B i.e. no data members or functions So, when I create an instance of class B, then I find that it has its own variable at different address and it also has a member function. How can it have its own of copy members if it they aren't copied?
Is that what do we mean by code reuse in inheritance?
Edit:
Updated my code to reflect what I meant by copying of variables.
Code is never copied during inheritance. But when the child object (class B) is created or instantiated at run time, it inherits the functionality and attributes of the parent class/object (class A).
the code from class A does NOT copied to class B in the sense that there is only one place the code is written.
however, and here cones the Reusable part, when using class b u can call the method and use the members, with respect to private, public, etd and thus does not have to write the same code for two class that do the same thing
for example if i have a circle and a square, and they both have a member called color that i want a method that change it, i do not need to write the method and the member twice, but have them inherit class Shape that will implement it once and then they both will be able to use that method, thus reusing one method in two places
I'm not sure "copied" is the right word (the compiler will only compile the code in class A once). As you have used public inheritance, class B actually is a special type of class A. As such, class B does have access to every (non-private) member of class A, so the code is re-used.
In addition, from the conversation in the comments:
No. Nothing is "copied", each instance of A and B has their own value for their own variables, except for any static data members. For static data members, again there is no copying going on; there is simply only one variable and that is shared by all instantiations of A and B.
In your example, you are comparing two different instances of two different classes. different instances means different base addresses to store instances data.
Perhaps a better test of whether a field of a class is copied over in derived classes is the following:
#include <iostream>
class A {
protected:
int f;
public:
void get() {
std::cout << "The address is: " << &f << std::endl;
}
};
class B : public A {
// ....
};
int main() {
B b;
b.get();
A *a = &b;
a->get();
return 0;
}
And the output is:
The address is: 0x7fff41d523f0
The address is: 0x7fff41d523f0
With that program, we can see that even though we have an instance of class B, its inherited content is physically the same as the one in the original class A. Note that it is also possible to redefine a class member in a derived class, but the original member will still be available if we coerce an instance of the derived class to the parent class (as I did in my example).
§1.8(2) of the C++ language standard defines what is meant by a subobject:
Objects can contain other objects, called subobjects. A subobject can be a member subobject (9.2), a base class subobject (Clause 10), or an array element. An object that is not a subobject of any other object is called a complete object.
These are examples of member subobjects and array elements, which you should be familiar with:
int a[5];
a[2]; // the third array element subobject of the complete object a
struct S { int x; }
S s;
s.x; // a member subobject of the complete object s
That leaves the remaining kind of subobject, the one which you are interested in: base class subobjects.
struct B { int x; }
struct D : public B { int y; }
D d;
d.y; // a member subobject of the complete object d
d.x; // a member subobject of a base class subobject of the complete object d
B &b = d; // a reference to a base class subobject of the complete object d
Every instance of a derived class contains an instance of its base class, as a base class subobject.
I also have some doubts regarding relation between inheritance and code re-use. This is my take on this.
Inheritance is a mechanism used to categorize and facilitate polymorphism. Using inheritance we can build a hierarchy of concepts separated in categories at different levels of abstraction. By doing this, we can efficiently use another OOP concept, polymorphism, which allows the same control code to manage all objects in a category even if they are different in their implementation.
I don't think that we use inheritance for code re-use purpose.

Object A is a member of B and the Object B is a member of A

I have a c++ where in classes A and B each one has a member of the other class. How can I solve this ?
class A {
B memberY;
}
class B {
A memberX;
}
You use pointers and forward declarations.
//A.h
class B; //forward declaration to class B
class A {
B* memeberY;
}
header for class B:
//B.h
class A; //forward declaration to class B
class B {
A* memeberX;
}
You can't do this with object instances, only with pointers, since an instance would require the compiler to know the full definition of the class.
Note that if memory management is assigned to the class, you should free the memory on the destructor. That means you should also override the copy constructor and operator = in your classes.
You can have one of the classes contain an object of the other class, but you have to include the other classes' header in the header. The other one would have to be solved with a forward declaration.
It isn't possible as you would like it. One of those classes has to be a pointer to the other one. You cannot have a recursive relationship of actual objects -- the size of the object would be infinite.
So you probably need something like this:
struct B;
struct A
{
B * myB;
};
struct B
{
A * myA;
};
Now, construction becomes a problem since they both need a reference to each other. That is why I can't provide you with a constructor, since I don't know how you will construct these objects.
You now also have a cleanup problem, since presumably one of these objects owns the other -- they both can't own each other. That excludes the use of unique_ptr. I would have used smart_ptr, but then you still have a memory link unless you have some function to break the circular reference.
But if you'd better indicate why you want to do this perhaps a more appropriate answer can be given.

C++ Inheritance. Changing Object data Types

I am having trouble with forcing data type changes has on my own objects. I have a base class say A and two classes derived from A called B and C. I pass objects B and C to a function that checks which type of object it is (B or C). Here is some example code below and the question to my problem:
enum ClassType {"B", "C"};
class A {
protected:
m_Type;
public:
ClassType Type() { return m_Type}
...
...
};
class B : public A {
otherMemberFunctions();
}
class C : public A {
otherMemberFunctions();
}
void WhatType(vector<A*>* candidates){
vector<B*> b_candidates(0);
vector<C*> c_candidates(0);
for(int i = 0; i < candidates->size(); i++){
if(candidates->at(i)->Type() == B ){
B* b = (B*) candidates->at(i);
b_candidates(b);
}
//Same idea for Object C
}
}
I would then use WhatType(vector<A*>* candidates) as follows
vector<B*>* b_example
WhatType((vector<A*>*) b_exmaple)
When I have filled the new vector b_candidates in the function WhatType. Will I still have access to the member functions in the B object or will I only have the access to the member functions in the base class A?
I am confused to what happens with the object when I change the type of the object.
Here
WhatType((vector<A*>*) b_exmaple)
and here
B* b = (B*) candidates->at(i);
When you receive a pointer to a polymorphic object you have two types: the "static" type of the object, which, in your case, will be A *, and its "dynamic" or "real" type, that depends on what was actually assigned to it.
Casting your A * to B * forces the compiler to consider that pointer as a pointer to B; this is safe as long as you actually know that that pointer is actually a pointer to B, otherwise the compiler will start writing nonsensical code (invoking B methods on data of another type).
The checks you are trying to implement are a homegrown version of RTTI, which is a mechanism that allows you to know which is the "real type" of a pointer or a reference to a polymorphic class, and to perform that kind of casts safely. Check out typeid and dynamic_cast on your C++ manual for more info about it. (Incidentally, IIRC dynamic_cast is not only for safety in case the dynamic type is wrong, but it may perform also some extra magic on your pointer if you use it in complicated class hierarchies; so, avoid C-style casting for polymorphic classes)
By the way, in general it's considered "code smell" to have to manually check the "real type" of the pointer in order to cast it and use its methods: the OOP ideal would be being able to do the work only though virtual methods available in the base class.
Big warning: RTTI works only on polymorphic classes, i.e. classes that have at least one virtual method. On the other hand, if you are building a class hierarchy where objects are being passed around as pointers to the base class you'll almost surely want to have a virtual destructor, so that's no big deal.
Since you cast to B*, you will have access to B's members.
The actual type of the objects does not change, of course, but if you only have a pointer (or reference) to the base class you can not access fields specific to the sub-classes.
What you can do to access sub-class fields is to use dynamic_cast to cast it to the sub-class:
A *a = new B; // We cant reach the members of class B in a
B *b = dynamic_cast<B *>(a); // But now we have a proper pointer to B
Ok, so if you had an object of type B instantiated on the heap and held by a pointer of type A. you can only see type A's member functions, to access type B's member functions you have to static_cast<B*> which is what the ... "(B*)" ... is doing.
dynamic cast is better as it will return a null if the conversion is not possible. but of course it happens a run-time so there's a penalty.
As B and C are À derived, a vector<B *> and vector<C *> contains A base class objects. If you ensure to set your A::m_Type attribute in your constructor, you will no have problems:
enum ClassType {'B', 'C'}; // see I modified your definition
class A {
protected:
ClassType m_Type;
public:
ClassType Type() { return m_Type};
...
...
};
class B : public A {
public:
B() : m_Type('B') {}
....
};
Using this, you will check without problems your B and Cobjects. After that, as you are casting base objects to derived ones, you will have fully access to their public methods and attributes.

C++ allocate objects on heap of base class with protected constructors via inheritance

I have a class with protected constructor:
class B {
protected:
B(){};
};
Now I derive from it and define two static functions and I manage to actually create objects of the class B, but not on the heap:
class A : public B {
public:
static B createOnStack() {return B();}
//static B* createOnHeap() {return new B;} //Compile time Error on VS2010
};
B b = A::createOnStack(); //This works on VS2010!
The question is: 1) Is VS2010 wrong in allowing the first case? 2) Is it possible to create objects of B without modifying B in any way (no friendship and no extra functions).
I am asking, because it is possible to make something similar when dealing with instances of B and its member functions, see:
http://accu.org/index.php/journals/296
Thank you in advance for any suggestion!
Kind regards
Yes, this code is non-compliant. This is related to special rules for protected member access (C++03 draft, 11.5/1):
When a friend or a member function of a derived class references a protected nonstatic member function or
protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11.10). Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5).
When you use B() or new B(), you're effectively using the constructor through a pointer to the base class.
You can create an object of type A (I assume that A is as posted - no additional members/non-static functions) and use it instead. If you're creating it on stack, everything should work fine, unless you're trying to assign other objects of type B to it. If you're creating it on heap, everything is fine as long as B's destructor is virtual. If B's destructor is not virtual, and you're returning new A() as a B*, then deleting the pointer is technically undefined behavior (5.3.5/3:
In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.
However you'll probably find it working fine in practice, so you can rely on the actual behavior if there is no other workaround (i.e. use it as a last resort).
There is a common misunderstanding on what protected actually means. It means that the derived class can access that particular member on itself not on other objects. The compiler should have rejected both functions as in both cases it is accessing the constructor of an object that is not of the derived type.
Another example, easier to discuss for its correctness would be:
struct base {
protected:
int x;
};
struct derived : base{
static void modify( base& b ) {
b.x = 5; // error
}
};
The commented line is an error as it is trying to modify an object of type base, not necessarily a derived object. If the language allowed that code to compile, then you would be able to modify an object of type base or even objects of types derived1, derived2... effectively breaking access rules.
struct derived2 : base {};
int main() {
base b;
derived2 d;
derived::modify( b ); // modifying a base!!!
derived::modify( d ); // modifying a derived2!!!
}