How to make virtual functions of a super class overrideable for grandchildren in C++? [duplicate]

孤街浪徒 提交于 2021-02-05 06:37:32

问题


Hey guys here is some code I am going to run, issue is it doesn't work the way I intend to. I am unable to figure out what's wrong with it. I am c++ noob please help.

#include <iostream>
#include <cmath>
#include <stdexcept>
using namespace std;

/**
 * Super class
 */
class Shape
{
protected:
    int _dimensions;
public:
    Shape() : _dimensions{0}
    {};
    Shape(int dims) : _dimensions{dims}
    {};

    virtual double getArea() {};
    // Because some shapes have no volume.  
    virtual double getVolume() {};  

    void setDimensions(int dim)
    {
        this->_dimensions = dim;
    };
    int getDimensions()
    {
        return this->_dimensions;
    };
};


/** 
 * Extended classes
 */
class TwoDimensionalShape : public Shape
{
public: 
    TwoDimensionalShape() : Shape{2}
    {};
    // This should throw an error
    double getVolume() {
        throw logic_error("This shape ain't got area!");
    };  
};

class ThreeDimensionalShape : public Shape
{
public: 
    ThreeDimensionalShape() : Shape{3} {};
};


/**
 * Final Concrete classes extending extended classes
 */
class Circle : public TwoDimensionalShape
{
protected:
    double _radius;
public:
    Circle(double r) : _radius{r}
    {};
    double getArea()
    {
        // pi*r^2
        return M_PI * pow(_radius, 2);
    }
};

class Square : public TwoDimensionalShape
{
protected:
    double _side;
public:
    Square(double s) : _side{s}
    {}
    double getArea()
    {
        // s^2
        return pow(_side, 2);
    }
};

class Triangle : public TwoDimensionalShape
{
protected:
    double _base, _height;
public:
    Triangle(double b, double h) : _base{b}, _height{h}
    {};
    double getArea()
    {
        // b*h/2
        return _base * _height / 2;
    }
};

class Sphere : public ThreeDimensionalShape
{
protected:
    double _radius;
public:
    Sphere(double r) : _radius{r}
    {}
    double getArea()
    {
        cout << 4 * M_PI * pow(_radius, 2) << endl;
        return 4 * M_PI * pow(_radius, 2);
    }
    double getVolume()
    {
        return (4/3) * M_PI * pow(_radius, 3);
    }
};

class Cube : public ThreeDimensionalShape
{
protected:
    double _side;
public:
    Cube(double s) : _side{s}
    {};
    double getArea()
    {
        // surface area = 6*a^2
        return 6 * pow(_side, 2);
    }
    double getVolume()
    {
        // a^3
        return pow(_side, 3);
    }
};

class Tetrahedron : public ThreeDimensionalShape
{
protected:
    double _side;
public:
    Tetrahedron(double s) : _side{s}
    {};
    double getArea()
    {
        // sqrt(3)*a^2
        return sqrt(3) * pow(_side, 2);
    }
    double getVolume()
    {
        // a^3/6sqrt(2)
        return pow(_side, 3) / (6 * sqrt(2));
    }
};

int main()
{
    Shape arr[2];
    arr[0] = Circle{10};
    arr[1] = Sphere{10};

    // This one is accessing the right method.
    cout << "Area of circle: " << arr[0].getArea() << endl; 
    // This one should access the parent, but accesses the grand parent!
    // even if it is overridden in parent.
    cout << "Volume of circle: " << arr[0].getVolume() << endl; 

    // Both of these are accessing methods on grand parent rather than their own!!
    cout << "Area of sphere: " << arr[1].getArea() << endl;
    cout << "Volume of sphere: " << arr[1].getVolume() << endl; 

    return 0;
}

I don't know why the array methods keep accessing the grand parent functions in the last three lines, but the right method on the first.


回答1:


You are experiencing Object Slicing. The portion of your code below does that:

Shape arr[2];
arr[0] = Circle{10};
arr[1] = Sphere{10};

Each of the assignments above invokes the copy assignment operator of Shape and slices off objects of the subclass. You can achieve your intention by using references or pointers:

std::unique_ptr<Shape> arr[2];
arr[0] = std::make_unique<Circle>(10);
arr[1] = std::make_unique<Sphere>(10);



回答2:


This is a case of object slicing. You need to put your objects as pointers, preferably as std::unique_ptr<> into your array - or again preferably a std::vector<>

Try this:

#include <memory>
#include <vector>

// ...

int main()
{
    std::vector<std::unique_ptr<Shape>> vec(2);
    vec[0] = std::make_unique<Circle>(10);
    vec[1] = std::make_unique<Sphere>(10);

    // This one is accessing the right method.
    cout << "Area of circle: " << vec[0]->getArea() << endl;
   // This one should access the parent, but accesses the grand parent!
    // even if it is overridden in parent.
    cout << "Volume of circle: " << vec[0]->getVolume() << endl;

    // Both of these are accessing methods on grand parent rather than their own!!
    cout << "Area of sphere: " << vec[1]->getArea() << endl;
    cout << "Volume of sphere: " << vec[1]->getVolume() << endl;

    return 0;
}


来源:https://stackoverflow.com/questions/44343888/how-to-make-virtual-functions-of-a-super-class-overrideable-for-grandchildren-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!