c++:所包含对象的确切类型,无需强制转换

发布于 2024-11-05 08:15:36 字数 1046 浏览 4 评论 0原文

我得到了经典的形状层次结构示例...

struct Shape { // abstract type
    Shape (int x, int y);

    int x;
    int y;
};

struct Rectangle : public Shape {
    Rectangle (int x, int y, int w, int h);

    int w;
    int h;
};

struct Circle : public Shape {
    Circle (int x, int y, int r);

    int r;
};

一个形状容器,其中填充了矩形和圆形

std::list<Shape*> container;

以及打印功能(在我的例子中,这些是碰撞检测功能)

void print_types (Shape&, Shape&) {
    std::cout << "Shape, Shape" << std::endl;
}

void print_types (Rectangle&, Rectangle&) {
    std::cout << "Rectangle, Rectangle" << std::endl;
}

void print_types (Rectangle&, Circle&) {
    ...

当然,当我这样做时:

std::list<Shape*> it;
Rectangle r (0, 0, 32, 32);

for (it = container.begin(); it != container.end(); it++)
     print_types(r, **it);

我不想只打印“形状,形状”线。我知道虚拟方法、dynamic_casts 和访问者。但是,有没有什么优雅的方法可以在没有这些解决方案的情况下摆脱它并保留我的外部功能?

I got the classic Shape hierarchy example...

struct Shape { // abstract type
    Shape (int x, int y);

    int x;
    int y;
};

struct Rectangle : public Shape {
    Rectangle (int x, int y, int w, int h);

    int w;
    int h;
};

struct Circle : public Shape {
    Circle (int x, int y, int r);

    int r;
};

a Shapes container, filled with Rectangles and Circles

std::list<Shape*> container;

and printing functions (in my case, those are collision detection functions)

void print_types (Shape&, Shape&) {
    std::cout << "Shape, Shape" << std::endl;
}

void print_types (Rectangle&, Rectangle&) {
    std::cout << "Rectangle, Rectangle" << std::endl;
}

void print_types (Rectangle&, Circle&) {
    ...

Course, when I'm doing this:

std::list<Shape*> it;
Rectangle r (0, 0, 32, 32);

for (it = container.begin(); it != container.end(); it++)
     print_types(r, **it);

I don't want to print only "Shape, Shape" lines. I know virtual methods, dynamic_casts and visitors. But is there any elegant way to get out of it without those solutions and keep my external functions ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

×眷恋的温暖 2024-11-12 08:15:36

您可能应该坚持使用虚函数并且只有一个 print_types 函数

void print_types(Shape&)

然后将一个虚 PrintName 函数添加到基类并在派生类中重写它。

这是最优雅的方式。

You should probably stick with virtual functions and have only one print_types function

void print_types(Shape&)

Then add a virtual PrintName function to the base class and override it in the derived class.

This IS the most elegant way.

欢烬 2024-11-12 08:15:36

简短的回答是否定的,函数调用在编译时解决。所以(AFAIK)无法使用现有的免费函数来做到这一点。

我相信您必须投资双重调度机制,或者做@Peter在他的回答中建议的事情(听起来更优雅)。

The short answer is no, function calls are resolved at compile-time. So there is no way (AFAIK) to do this with your existing free functions.

I believe you will have to invest in a double-dispatch mechanism, or do what @Peter suggests in his answer (which sounds more elegant).

浅唱々樱花落 2024-11-12 08:15:36

我不能称其为优雅,它有几个陷阱,但在 dynamic_cast 之前执行此操作的经典方法是拥有一个 virtual 函数,例如 virtual char * name(),在 Shape 中,并让每个派生类重写该函数以返回正确的名称。

最明显的陷阱是您必须手动维护整个过程。

I can't call it elegant, and it has several pitfalls, but the classic way to do this before dynamic_cast was to have a virtual function, say virtual char* name(), in Shape and have each derived class override that function to return the correct name.

The most obvious pitfall is that you must maintain the whole thing by hand.

溺渁∝ 2024-11-12 08:15:36

回应问题的编辑:

最好的解决方案仍然是找到一个能够提供所需内容的虚拟方法。为了检测形状碰撞,也许您可​​以有一个函数将每个形状转换为多边形(一组线)并对其进行检测。

C++ 使用您在编译时声明的类型来选择要调用的重载函数;它没有能力在运行时做出选择。这就是为什么您每次都会看到“Shape,Shape”作为输出。有一种方法可以帮助编译器摆脱困境,但这会很乏味。尝试将每个 Shape* 转换为适当的类型,如果成功,您可以调用更具体的函数。

我并不是真的提倡这样做;你可以看到只有两个形状它是如何失控的,想象一下当你添加更多形状时它会变得多么难看!它仍然展示了如何在 C++ 中执行您尝试执行的操作。

void print_types (Rectangle*, Rectangle*) {
    std::cout << "Rectangle, Rectangle" << std::endl;
}

void print_types (Rectangle*, Circle*) {
    ... 

void print_types (Rectangle* left, Shape* right) {
    Rectangle* rightRect = dynamic_cast<Rectangle*>(right);
    if (rightRect != NULL) {
        print_types(left, rightRect);
        return;
    }
    Circle* rightCirc = dynamic_cast<Circle*>(right);
    if (rightCirc != NULL) {
        print_types(left, rightCirc);
        return;
    }
    throw /* something to indicate invalid shape */;
}

void print_types (Circle* left, Shape* right) {
    ...

void print_types (Shape* left, Shape* right) {
    Rectangle* leftRect = dynamic_cast<Rectangle*>(left);
    if (leftRect != NULL) {
        print_types(leftRect, right);
        return;
    }
    Circle* leftCirc = dynamic_cast<Circle*>(left);
    if (leftCirc != NULL) {
        print_types(leftCirc, right);
        return;
    }
    throw /* something to indicate invalid shape */;
}

Responding to the edit of the problem:

The best solution is still to find a virtual method that will deliver what is required. For detecting shape collisions, perhaps you could have a function that converts each shape to a polygon (set of lines) and do the detection on that.

C++ uses the type you declared at compile-time to select which overloaded function to call; it doesn't have the ability to make that selection at run-time. That's why you're seeing "Shape,Shape" as output each time. There's a way to help the compiler out but it's going to be tedious. Try to convert each Shape* to the appropriate type, and if it succeeds you can call a more specific function.

I'm not really advocating this; you can see how it gets out of hand with just two shapes, imagine how ugly it gets as you add more! Still it shows how to do what you were trying to do in C++.

void print_types (Rectangle*, Rectangle*) {
    std::cout << "Rectangle, Rectangle" << std::endl;
}

void print_types (Rectangle*, Circle*) {
    ... 

void print_types (Rectangle* left, Shape* right) {
    Rectangle* rightRect = dynamic_cast<Rectangle*>(right);
    if (rightRect != NULL) {
        print_types(left, rightRect);
        return;
    }
    Circle* rightCirc = dynamic_cast<Circle*>(right);
    if (rightCirc != NULL) {
        print_types(left, rightCirc);
        return;
    }
    throw /* something to indicate invalid shape */;
}

void print_types (Circle* left, Shape* right) {
    ...

void print_types (Shape* left, Shape* right) {
    Rectangle* leftRect = dynamic_cast<Rectangle*>(left);
    if (leftRect != NULL) {
        print_types(leftRect, right);
        return;
    }
    Circle* leftCirc = dynamic_cast<Circle*>(left);
    if (leftCirc != NULL) {
        print_types(leftCirc, right);
        return;
    }
    throw /* something to indicate invalid shape */;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文