C++ c++;:不带强制转换的包含对象的确切类型

C++ c++;:不带强制转换的包含对象的确切类型,c++,oop,inheritance,polymorphism,covariance,C++,Oop,Inheritance,Polymorphism,Covariance,我得到了经典的形状层次结构示例 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 (i

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

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;
std::列表容器;
和打印功能(在我的例子中,这些是碰撞检测功能)

void打印类型(形状和,形状和){

std::cout您可能应该坚持使用虚拟函数,并且只有一个print_types函数

void print_types(Shape&)
然后向基类添加一个虚拟PrintName函数,并在派生类中重写它


这是最优雅的方式。

简短的回答是否定的,函数调用在编译时解决。因此,对于现有的自由函数,没有办法(AFAIK)做到这一点


我相信你将不得不投资于a,或者按照@Peter在他的答案中的建议去做(听起来更优雅)。

我不能称之为优雅,它有几个陷阱,但在
动态\u cast
之前,做这件事的经典方法是使用
虚拟
函数,比如
虚拟字符*name()
,并让每个派生类重写该函数以返回正确的名称


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

对问题的编辑做出响应:

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

C++使用您在编译时声明的类型来选择要调用的重载函数;它无法在运行时进行选择。这就是为什么您会看到“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 */;
}
void打印类型(矩形*,矩形*){

cout优雅的方式是使用设计好的语言。这意味着“虚拟方法、动态类型转换和访问者”@Mark:理想情况下不是动态强制转换,但是…@Oli,语言的每一个特性都是有原因的。我曾经发现一个动态强制转换的例子是有用的,如果你不同意,你可以在那里留下一个注释:@Mark:我不反对动态强制转换偶尔会有使用
+1:这是一个比我的双重分派建议更干净的解决方案手势。事实上,我不是在打印类型,而是在检查表单之间的冲突……也许我应该编辑我的初始帖子。我已经尝试过这个解决方案,它非常有效,但我正在寻找一种更“简单”的方法来做这件事。
void print_types(Shape&)
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 */;
}