如何访问sideA
类的height
和Triangle
成员,以及如何访问sideA
类的Square
,它们都是派生的来自Shape
类?
实现该目标的正确方法是什么?
Shapes.h:
class Shape
{
public:
virtual double getArea() = 0;
};
class Triangle : public Shape
{
public:
double sideA = 3;
double height = 2;
double getArea() {
return 0.5 * sideA * height;
}
};
class Square : public Shape
{
public:
double sideA = 4;
double getArea() {
return sideA * sideA;
}
};
Main.cpp:
int main()
{
Shape* sh = new Triangle();
std::cout << sh->getArea() << std::endl;
std::cout << sh->??? //get the height of triangle
delete sh;
}
答案 0 :(得分:3)
您正尝试访问通过您定义的界面无法获得的信息,class Shape
仅允许访问区域。
要获得高度,正确的方法是扩展界面以提供该信息。
class Shape
{
public:
virtual double getArea() = 0;
virtual double getHeight() = 0;
};
class Triangle : public Shape
{
public:
double sideA = 3;
double height = 2;
double getArea() {
return 0.5 * sideA * height;
}
double getHeight() {
return height;
}
};
class Square : public Shape
{
public:
double sideA = 4;
double getArea() {
return sideA * sideA;
}
double getHeight() {
return sideA;
}
};
答案 1 :(得分:2)
您可以将变量声明为num_nulls
而不是Triangle*
,这样您就可以访问派生类和基类的方法和变量:
Shape*
要安全使用int main()
{
Triangle* sh = new Triangle();
Square* sh2 = new Square();
std::cout << sh->getArea() << std::endl; //3
std::cout << sh2->getArea() << std::endl; //16
std::cout << sh->sideA << std::endl; //3
std::cout << sh2->sideA << std::endl; //4
delete sh;
}
,您应该有一个虚拟析构函数
delete sh
由于您已经有了一个抽象类,为什么不使用它来访问派生类中的数据:
class Shape
{
public:
virtual double getArea() = 0;
virtual ~Shape(){} //virtual destructor
};
答案 2 :(得分:2)
由于基类具有virtual
函数 1 ,因此可以使用dynamic_cast
转换来检查指向它的指针是否实际上是指向其派生对象之一的指针类。如果不是'tested'类的 ,它将返回nullptr
;如果是派生的类,则将返回可用的指针:
int main()
{
Shape* sh = new Triangle();
std::cout << sh->getArea() << std::endl;
if (dynamic_cast<Square*>(sh) != nullptr) { // Check for a valid Square pointer
Square* sq = dynamic_cast<Square*>(sh);
std::cout << sq->sideA << std::endl;
}
else if (dynamic_cast<Triangle*>(sh) != nullptr) { // Check for a valid Trianlge pointer
Triangle* tr = dynamic_cast<Triangle*>(sh);
std::cout << tr->height << std::endl;
}
else {
std::cout << "Unspecified shape type: height unknown!" << std::endl;
}
delete sh;
return 0;
1 注意,因为在您的Shape
类中有一个虚函数,所以还应该给它一个虚析构函数:
class Shape {
public:
virtual double getArea() = 0;
virtual ~Shape() { }
};
有关是否需要虚拟析构函数的更多讨论,请参见此处:When to use virtual destructors?。
dynamic_cast
选项的使用是很有用的,因为如果您从第三方基类派生类,则这可能是仅解决方案修改,因此无法向其添加getHeight()
函数的等效项。
答案 3 :(得分:2)
Shape
没有height
。您正在多态使用三角形。这意味着您拥有Shape*
,并且无论对象的实际类型是什么,都只能使用Shape
的接口。如果要使用Triangle
,请使用Triangle
而不是Shape
。如果仍然想多态使用Triangle
和Rectangle
,则应将通用接口放入基类中。在您的情况下,两个都有sideA
,因此您可以这样做:
struct Shape {
double sideA = 3;
virtual double getArea() = 0;
virtual ~Shape(){}
};
struct Triangle : public Shape {
double height = 2;
double getArea() {
return 0.5 * sideA * height;
}
};
struct Square : public Shape {
double getArea() {
return sideA * sideA;
}
};
int main() {
Shape* sh = new Triangle();
std::cout << sh->sideA;
delete sh;
}
PS:以上并非全部事实。如果您有一个Shape*
并且知道它是Triangle*
,则可以使用dynamic_cast
,但是这样做的强制转换通常是不良设计的标志。您应该努力编写不需要强制转换的类。