0

I try to understand inheritance up to the hilt in OOP. So, I've exercised some tries. But, two points I'm stuck that one of them is object slicing. The other one is calling order of destructors. Why is Box {carton} need for right copy ctor? If Box {carton} is added, how can be carton type converted to Box type(I absolutely don't understand it).

// right ctor
/*
Carton(const Carton& carton) : Box {carton}, material {carton.material}
{ std::cout << "Carton copy constructor" << std::endl; }
*/

Code:

#include <iomanip>
#include <iostream>
#include <string>
using namespace std;

class Box
{
protected:
    double length;
    double width;
    double height;
public:
    // Constructors
    Box(double lv, double wv, double hv);

    Box(double side) : Box {side, side, side}
    { std::cout << "Box(double) called.\n"; }

    Box() { std::cout << "Box() called.\n"; }

    double volume() const
    { return length * width * height; }

    double getLength() const { return length; }
    double getWidth() const { return width; }
    double getHeight() const { return height; }
    ~Box()
    { cout << "box destructor" << endl; }

    void print();

    // copy ctor
    Box(const Box& box) : length{box.length}, width{box.width}, height{box.height}
    { std::cout << "Box copy constructor" << std::endl; }
};


class Carton : public Box
{
private:
    string material {"Cardboard"};
public:
    Carton(double lv, double wv, double hv, const string desc) : Box {lv, wv, hv}, material {desc}
    { std::cout << "Carton(double,double,double,string) called.\n";}

    Carton(const string desc) : material {desc}
    { std::cout << "Carton(string) called.\n";}

    Carton(double side, const string desc) : Box::Box(side),material {desc}
    { std::cout << "Carton(double,string) called.\n";}

    Carton() { std::cout << "Carton() called.\n";}

    ~Carton()
    { cout << "cartoon destructor" << endl; }

    void print();

    // right ctor
    /*
    Carton(const Carton& carton) : Box {carton}, material {carton.material}
    { std::cout << "Carton copy constructor" << std::endl; }
    */

    Carton(const Carton& carton) : material {carton.material}
    { std::cout << "Carton copy constructor" << std::endl; }

};

int main()
{
    // Declare and initialize a Carton object
    Carton carton(20.0, 30.0, 40.0, "Glassine board");
    Carton cartonCopy(carton);             // Use copy constructor
}

// Ctor
Box::Box(double lv, double wv, double hv) : length {lv}, width {wv}, height {hv}
{ std::cout << "Box(double, double, double) called.\n"; }

// Redefinitions
void Box::print()
{
    cout << "Box printttttt" << endl;
}
void Carton::print()
{
    cout << "Carton printttttt" << endl;
}
askque
  • 319
  • 2
  • 9

1 Answers1

0

Remember that inheritance is a "is a" relationship. A Carton is a Box, which is why you can use a Carton when a Box is expected.

However be careful of the object slicing problem. If a function takes a Box argument by value, and you pass a Carton object, the function will get only the Box part.


Also, you have another problem, in that your print function is not virtual. That means even if you have a pointer or reference to Box and pass a Carton the Carton::print function will not be called.

Lets illustrate this with an example:

void foo(Box const& box)
{
    box.print();
}

int main()
{
    Carton carton(...);
    foo(carton);
}

The above sample code will not have any object-slicing problems because the foo function gets a reference to the base class. However, it will print

Box printttttt

If you make Box::print virtual

virtual void print();

Then the above code will print

Carton printttttt
Community
  • 1
  • 1
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621