Derive a class from two same-Derived classes

81 views Asked by At

exercise.h is as below

#ifndef EXERCISE_H_
#define EXERCISE_H_

// ROOT namespace
namespace root{

// USHORT definition
typedef unsigned short ushort;

// PI DEFINITION
const double PI = 3.141592;

class shape {
    double height;
    double width;
public:
    shape(double h = 1, double w = 1);
    virtual ~shape(){}
    double getHeight() const;
    double getWidth() const;
    virtual double area() const = 0;
};

class rectangle : virtual public shape{
public:
    rectangle(double height = 1, double width = 1);
    double area() const;
};

class triangle : virtual public shape {
public:
    triangle(double h = 1, double w = 1);
    double area() const;
};

class someShape : public rectangle, public triangle{
public:
    someShape(double rh = 1, double rw = 1, double th = 2, double tw = 2);
    double area() const;
    double trySomething() const;
};




} // NAMESPACE

#endif /* EXERCISE_H_ */

exercise.cpp is like this

#include <iostream>
#include <cmath>
#include "exercise.h"
using std::cout;
using std::cin;
using std::endl;
using root::ushort;

// BEGIN SHAPE CLASS
root::shape::shape(double h, double w) : height(h), width(w){

}

double root::shape::getHeight() const{
    return this->height;
}

double root::shape::getWidth() const{
    return this->width;
}
// END SHAPE CLASS


// BEGIN RECTANGLE CLASS
root::rectangle::rectangle(double h, double w) : shape(h,w){

}

double root::rectangle::area() const{
    return this->getHeight() * this->getWidth();
}

// END RECTANGLE CLASS
// BEGIN TRIANGNLE CLASS
root::triangle::triangle(double h, double w) : shape(h,w){

}

double root::triangle::area() const{
    return this->getHeight() * this->getWidth() / 2;
}
// END TRIANGLE CLASS



root::someShape::someShape(double rh, double rw, double th, double tw) : rectangle(rh,rw), triangle(th,tw){

}

double root::someShape::area() const {
    return rectangle::area();
}

double root::someShape::trySomething() const{
    return triangle::getHeight() * rectangle::getWidth();
}

and in main

#include <iostream>
#include "exercise.h"
using std::cout;
using std::cin;
using std::endl;


int main(){
    root::shape *ptrShape;
    ptrShape = new root::someShape(3,2,4,3);
    cout << "shape area: " << ptrShape->area() << endl;

    delete ptrShape;

}

when i create an someShape object i only got the default values. although i initilize the deriving class. And there is another thing. It is the fact that we derived Rectangle and Triangle seperately and from those object we derived an other object. How will compiler decide which area() function to use?

2

There are 2 answers

0
Holt On BEST ANSWER

The problem here is that you have a virtual inheritance from shape to rectangle and triangle, so the constructors of rectangle and triangle does not initialize shape. Your someShape constructor is equivalent to:

root::someShape::someShape(double rh, double rw, double th, double tw) : 
    rectangle(rh,rw), triangle(th,tw), shape() {

}

Which is why you get the default values 1 and 1. Also, note that since you have virtual inheritance, you cannot store different height and width for the rectangle and the triangle. Your constructor should be something like:

root::someShape::someShape(double h, double w) : 
    rectangle(h, w), triangle(h, w), shape(h, w) {

}

Or if you do not want to have a single instance of shape, you should remove the virtual inheritance of rectangle and triangle.

See also c++ virtual inheritance.

0
A.N On

The problem is that you are doing virtual inheritence i.e. rectangle and triangle inherit shape using the virtual keyword. So there is a single instance of shape class that is shared among the derived classes. Hence the constructor calls from rectangle and triangle to shape are completely skipped by the compiler.

Check this for more details: http://www.cprogramming.com/tutorial/virtual_inheritance.html https://isocpp.org/wiki/faq/multiple-inheritance