noob
noob

Reputation: 93

Inheritance in C++

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

  1. Is an instance of AA created
  2. If yes, what is it called and how can I reference it?
  3. If no, why is the constructor being called

Upvotes: 2

Views: 479

Answers (7)

Mooing Duck
Mooing Duck

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

Jayraj Srikriti Naidu
Jayraj Srikriti Naidu

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

Baltasarq
Baltasarq

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

Kerrek SB
Kerrek SB

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

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

Jonathan Sternberg
Jonathan Sternberg

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.

  1. Call AA constructor
  2. Initialize member fields
  3. Call BB constructor

When destruction happens, this happens in reverse.

  1. Call BB destructor
  2. Destroy member fields (specific to BB)
  3. Call AA destructor

Oh, 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

Andr&#233; Caron
Andr&#233; Caron

Reputation: 45284

  1. Is an instance of A created

Sort of. The BB b; code will allocate a BB instance. Part of that object is an AA.

  1. 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

Related Questions