Reputation: 93
I was messing around with inheritance in C++ and wanted to know if anyone had any insight on the way it functions. Code below
#include <iostream>
using namespace std;
class AA {
int aa;
public:
AA() {cout<<"AA born"<<endl;}
~AA(){cout<<"AA killed"<<endl;}
virtual void print(){ cout<<"I am AA"<<endl;}
};
class BB : public AA{
int bb;
public:
BB() {cout<<"BB born"<<endl;}
~BB() {cout<<"BB killed"<<endl;}
void print() {cout<<"I am BB"<<endl;}
};
class CC: public BB{
int cc;
public:
CC() {cout<<"CC born"<<endl;}
~CC(){cout<<"CC killed"<<endl;}
void print() {cout<<"I am CC"<<endl;}
};
int main()
{
AA a;
BB b;
CC c;
a.print();
b.print();
c.print();
return 0;
}
so I understand that when you inherit something you inherit constructors and destructors. So when I do , "BB b" it prints "AA born". So the question I have
Upvotes: 2
Views: 479
Reputation: 66961
This is a little easier to understand when I give the structs more meaningful names:
class Animal;
class Dog : public Animal;
class Beagle : public Dog;
[When I create a Dog b
...]
Is an instance of Animal
created?
Yes, creating a Dog
also creates an Animal
, because the Dog
is an Animal
.
If yes, what is it called and how can I reference it?
The Dog b
is the Animal
instance. If you wanted to explicitly call the Animal
versions of the method, you could use b.Animal::print()
to tell the compiler
to explicitly call the Animal
version of the function.
If no, why is the constructor being called?
The Dog b
is an an Animal
, so constructing a Dog
also constructs itself as an Animal
.
http://coliru.stacked-crooked.com/a/522371508982b56f
Upvotes: 0
Reputation: 99
Inheritance in c++ means the ability of objects in one class to inherit properties of another class which implements the reusablity concept. This means that it is not necessary to create a new methods and just override the existing one, if required. Saves a lot of work.
Upvotes: -1
Reputation: 12222
In object-oriented languages, there are two main ways of creating objects that inherit from another one: concatenation and delegation. The first one is the most popular, the second is used in prototype-based languages.
Concatenation means that when B inherits from A, there are two parts in the object: in the first part of the object (of length equal to the size of A), the attributes (member variables/fields in C++) of A live. In the other part, there lives whatever attributes B adds to the object. Constructors for each involved class (A and B) are executed so all parts (all attributes) are initialized correctly.
Though the object is managed as a single unit, you can point it with a pointer of class A. In that case, the pointer only lets you see the first part, the part pertaining to class A (i.e. its attributes), but not the attributes from B, since the pointer can only see from the beginning to beginning + size of class A.
Say class A contains an integer x:
class A {
public: int x;
};
and B contains an integer y:
class B: public A {
public: int y;
} obB;
This means that an object of class B will have a length of 8 bytes (for 32 bits), the length of x plus the length of y, while the length of A is of only 4 bytes, the length of x. A pointer of class A to objB
:
A * ptrA = &objB;
will only see x
,
cout << ptrA->x << endl;
cout << ptrA->y << endl; // ERROR
while a pointer to B:
B * ptrB = &objB;
will be able to access both, x and y:
cout << ptrB->x << ',' << ptrB->y << endl;
In order to completely understand this, you need to know that ptrB->y
is roughly translated into *( ( (int *) ptrB ) + 1 )
, but that's another story.
Hope this helps.
Upvotes: 1
Reputation: 477514
A class that derives from a base class contains that base class as a subclass, so an instance of the derived class contains a base subobject.
The subobject is constructed first. The constructor that is used for that is yours to determine: If you don't say anything, the default constructor is used; otherwise, the constructor that you specify in the base initializer list is called. Example:
struct Base
{
Base() { } // default constructor
Base(int, double) { } // some other constructor
char q;
};
struct A : Base
{
};
struct B : Base
{
B() : A(12, 1.5) { }
};
Both A
and B
contain Base
as a subclass. When you say A a;
, the subobject's default constructor is called. When you say B b
, the subobjects other constructor is called, because you said so.
As a consequence, if the base class has no accessible default constructor, then you must specify an accessible constructor explicitly.
You can reference members of the subobject by qualifying the name: a.Base::q
or b.Base::q
. If the name is unambiguous, that's the same as just a.q
and b.q
. However, when you deal with overridden or hidden member functions (and maybe multiple virtual inheritance), being able to specify the subobject explicitly may be useful or even necessary.
Upvotes: 0
Reputation: 88771
Inheritance implements the "IS-A" relationship. Every BB
is therefore also an AA
.
You can see this in a number of ways, the easiest to demonstrate is:
BB b;
AA *aptr = &b;
Here your BB
instance b
is being pointed at by a pointer which only thinks of itself as pointing to an AA
. If BB
didn't inherit from AA
then that wouldn't be legal.
The interesting thing is that when you call:
aptr->print();
It still prints "I am BB", despite the fact that the pointer you used is of type AA *
. This happens because the print()
method is virtual
(i.e. polymorphic) and you're using a pointer. (The same would also happen with a reference too, but the type must be one of those for this behaviour to happen)
Upvotes: 2
Reputation: 6677
BB
is an instance of AA
. You don't need to access anything special, because you already have that type.
When BB
inherits from AA
, here's how it's constructed.
AA
constructorBB
constructorWhen destruction happens, this happens in reverse.
BB
destructorBB
)AA
destructorOh, and you have at least one virtual function inside of AA
. That means you need to make AA
's destructor virtual (or bad things will happen).
Upvotes: 2
Reputation: 45284
- Is an instance of A created
Sort of. The BB b;
code will allocate a BB
instance. Part of that object is an AA
.
- If yes, what is it called and how can I reference it?
Assuming the BB b;
variable declaration, your part-of-BB
AA
instance is called b
. If you want to call specific methods in AA
that are hidden by BB
methods, such as .print()
, you need to invoke them like so:
BB b;
b.AA::print();
Upvotes: 2