问题
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