如何使 C++ 中的孙子可以覆盖 super class 的虚函数?

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

大家好,这是我要使用的一些代码 运行,问题是它无法按照我的预期运行。我无法弄清楚它有什么问题。我是c++菜鸟,请帮忙。

#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;
}

我不知道为什么数组方法在最后三行中一直访问祖父函数,但第一行是正确的方法。

这是一个对象切片的案例。你需要把你的对象作为指针,最好是 std::unique_ptr<> 放入你的数组 - 或者再次最好是 std::vector<>

试试这个:

#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;
}

您遇到对象切片。下面的代码部分就是这样做的:

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

上面的每个赋值调用子类对象的Shapeslices的复制赋值运算符。您可以使用引用或指针来实现您的意图:

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