gpt4 book ai didi

c++ - 使用形状参数时,如何灵活地使用可以处理 2D 和 3D 形状的方法参数

转载 作者:行者123 更新时间:2023-11-28 05:48:06 24 4
gpt4 key购买 nike

我知道标题很烂。这里的问题是我有一个从形状类继承的 2D 和 3D 形状类

class Shape {
public:
virtual double area() = 0;//Calculates the area of some kind of shape
~Shape() { delete this; }
};

class Shape2D :public Shape {
public:
virtual double perimeter() = 0;//Calculates the perimeter of some kind of 2D-shape
~Shape2D() {};
};

class Shape3D :public Shape {
public:
virtual double volume() = 0;//Calculates the volume of some kind of 3D-shape, area function will return surface area
~Shape3D() {};
};

决定所有形状都默认有一个区域。在 2D 形状中,它将有一个虚拟周长方法以及来自 Shape 的面积。在 3D 形状中,它将有一个体积,并且虚拟面积方法将被视为表面积。

我采用的方法是在可以选择 2d 或 3d 形状的菜单中:在 2d 菜单中,我启动:

Shape2D * s = nullptr;

在 3d 菜单中,我将启动:

Shape3D * s = nullptr;

然后为了显示任何信息,我使用以下方法:

void displayShape2D(Shape2D *)

void displayShape3D(Shape3D *)

但是,我想采用的方式是声明:

Shape *s = nullputr;

在 main 的开头,然后在用户选择的任何形状,我可以设置:

s= new Triangle()

s = new cube();

初始化工作正常,但是当我尝试创建一个显示方法时,这就是我遇到问题的地方。我希望能够做到:

displayShape(Shape *s)

当给定一个 2d 形状并在我尝试的方法中时:

cout <<s->perimeter();

它会说周边成员不在形状类中。然后的问题是试图能够确定形状是 2d 还是 3d,然后显示 2d 的面积和周长或 3d 的表面积和体积。这是可能的还是在专用菜单中创建形状类型然后使用专用显示方法是唯一的出路?

最佳答案

虽然其他答案“有效”,但这不是我在这里采用的方法。基本上,您希望根据实例的动态类型执行不同的代码:这就是虚函数的用途。

所以只需添加一个(可能是纯的)虚拟 display Shape 的成员函数类并在派生类中相应地实现它。

dynamic_cast相反当您添加更多派生类或“进一步”派生的类时,这种方法不会中断。

最后:

~Shape() {
delete this;
}

这个析构函数在 C++ 中相当于拿着猎枪朝自己的脸开枪。对于堆栈或静态分配的实例,这将导致虚假释放(因为该实例从未从堆中分配),对于堆分配,它将导致双重释放(因为析构函数在释放占用的内存之前被调用)实例)。

在您的情况下,您必须做的是使析构函数成为虚拟的。否则,只有 Shape *不可能正确地销毁指向的实例!


这就是这种“显示”功能“普遍”实现的方式,至少据我所知:

struct Shape {
virtual void write_to(ostream &) const = 0;
virtual ~Shape() {}
};
struct Shape2D : public Shape {
void write_to(ostream & stream) const {
stream << "<2D, whooo>";
}
};
struct Shape3D : public Shape {
void write_to(ostream & stream) const {
stream << "<I got depth, man!>";
}
};

ostream & operator<<(ostream & stream, Shape const & shape) {
shape.write_to(stream);
return stream;
}

现在可以写任何Shape (当使用指针时,取消引用它)任何 ostream,C++“风格”:

std::unique_ptr<Shape> awesomeShape = std::make_unique<Shape2D>();
std::cout << "Awesome is: " << *awesomeShape << std::endl;

在这里,首先operator<<(ostream &, Shape &)被调用(对于任何 Shape 类似的东西)调用虚拟成员函数 write_to ,它以不同的方式为每个派生类实现(尽管在 Shape 中也可能有一个通用的实现!)。另见 this .


dynamic_cast 可能存在的问题当您加深层次结构时,就会出现这种方法:

struct ThickShape2D : public Shape2D {
// whatever
};

具有动态类型的实例 ThickShape2D也可以是dynamic_castShape2D ,因此您需要密切注意这些 if 子句的顺序。

但是,引用 Jarra McIntyre 的话:

I think it is worth mentioning that the design trade offs between using virtual functions and the above approach (and any other approaches) are complex. The above approach allows runtime dispatch on multiple types, and simplifies things such as (going back to the above) having multiple draw functions.

我完全同意。有访问者模式(也是非循环变体),可能是命令模式,如果需要更多信息,可以开始查看许多其他内容。有关(原始)RTTI 使用的广泛讨论,请参阅 this question and its answers .


作为最后的说明:我不确切知道您要建模的是什么,但考虑到继承通常不是可用的最佳方法。如果可能,prefer composition over inheritance . Entity component系统是一个很好看的东西。

(上面的段落包含6个链接,只是为了不要错过任何东西。)

关于c++ - 使用形状参数时,如何灵活地使用可以处理 2D 和 3D 形状的方法参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35821864/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com