访问子类变量的正确解决方案是什么?

时间:2020-04-25 13:34:14

标签: c++ class inheritance polymorphism

如何访问sideA类的heightTriangle成员,以及如何访问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;
}

4 个答案:

答案 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

由于您已经有了一个抽象类,为什么不使用它来访问派生类中的数据:

Here is how I would do it

class Shape
{
public:
    virtual double getArea() = 0;
    virtual ~Shape(){} //virtual destructor
};

看看smart pointers

答案 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?


编辑:在您的特定情况下,answer given by rustyx实际上是“正确”的方法;但是,了解/理解dynamic_cast选项的使用是很有用的,因为如果您从第三方基类派生类,则这可能是解决方案修改,因此无法向其添加getHeight()函数的等效项。

答案 3 :(得分:2)

Shape没有height。您正在多态使用三角形。这意味着您拥有Shape*,并且无论对象的实际类型是什么,都只能使用Shape的接口。如果要使用Triangle,请使用Triangle而不是Shape。如果仍然想多态使用TriangleRectangle,则应将通用接口放入基类中。在您的情况下,两个都有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,但是这样做的强制转换通常是不良设计的标志。您应该努力编写不需要强制转换的类。

相关问题