C++ 如何优先选择虚拟方法重写和继承

C++ 如何优先选择虚拟方法重写和继承,c++,inheritance,overriding,C++,Inheritance,Overriding,所以现在我有三节课形状,正方形,三角形三角形和正方形继承自形状。在Shape中,我有虚拟方法: 例如在三角形中我有: 现在,在我的主要方法中,我有: Shape* m[3]; m[0] = new Square; m[1] = new Triangle; m[2] = new Square; cout << m[0]->myMethod(*m[1]); cout << m[0]->myMethod(*m[2]); Shape*m[3]; m[0]=新的正方形

所以现在我有三节课<代码>形状,
正方形
三角形
<代码>三角形和
正方形
继承自
形状
。在
Shape
中,我有虚拟方法:

例如在
三角形中
我有:

现在,在我的主要方法中,我有:

Shape* m[3];
m[0] = new Square;
m[1] = new Triangle;
m[2] = new Square;
cout << m[0]->myMethod(*m[1]);
cout << m[0]->myMethod(*m[2]);
Shape*m[3];
m[0]=新的正方形;
m[1]=新三角形;
m[2]=新广场;
cout-myMethod(*m[1]);
cout-myMethod(*m[2]);
当我在第一个
cout
中调用它时,它工作正常,并转到
(Shape&tri)
方法,但在第二个
(Shape&tri)
方法。我理解为什么会发生这种情况,但是有没有办法让它转到
(Square&squ)
方法而不是
Shape


谢谢

< p>你正在寻找一个不存在于C++语言中的特性。在C++中,动态调度只从调用方发生,而不在任何参数上发生。p> 因此,当您调用
myMethod(*m[2])
时,
*m[2]
是一个
Shape
,因此它将调用
bool myMethod(Shape&)
,因为重载解析更喜欢这样

现在,如果您真的想在
三角形/正方形
案例中找到一些特别的东西,您可能需要看看双重分派:

virtual bool Triangle::myMethod(Shape& shape) {
    return shape.myMethodImpl(*this);
}
这样,您就可以:

virtual bool Square::myMethodImpl(Triangle& triangle) {
    // ...
}

只能通过第二次调度调用

> P>你正在寻找一个C++语言中不存在的特性。在C++中,动态调度只从调用方发生,而不在任何参数上发生。p> 因此,当您调用
myMethod(*m[2])
时,
*m[2]
是一个
Shape
,因此它将调用
bool myMethod(Shape&)
,因为重载解析更喜欢这样

现在,如果您真的想在
三角形/正方形
案例中找到一些特别的东西,您可能需要看看双重分派:

virtual bool Triangle::myMethod(Shape& shape) {
    return shape.myMethodImpl(*this);
}
这样,您就可以:

virtual bool Square::myMethodImpl(Triangle& triangle) {
    // ...
}

只能通过第二次调度调用

C++使用重载解析选择要调用的方法。重载解析完全基于参数的静态类型。如果被调用的重载是一个
虚拟
函数,它可能在派生类中被重写,在这种情况下,调用在运行时被分派到重写

据我所知,您希望系统根据对象和参数类型执行多重分派。C++不直接支持多调度,但有多种方法可以模拟。要处理所需的调度,您可以安排调用,以便在运行时找到适当的覆盖。一种方法是将函数拆分为多个版本

struct Square;
struct Triangle'
struct Circle;

struct Shape {
    virtual ~Shape() {}

    virtual bool doMethod(Square& s) { return doMethod(static_cast<Shape&>(s)); }
    virtual bool doMethod(Triangle& s) { return doMethod(static_cast<Shape&>(s)); }
    virtual bool doMethod{Circle& s) { return doMethod(static_cast<Shape&>(s)); }

    virtual bool doMethod(Shape&) = 0;
    virtual bool myMethod(Shape&) = 0;
};

struct Triangle: Shape {
    bool myMethod(Shape& other) { return other.doMethod(*this); }
    bool doMethod(Shape& other) { /* general case */ }
    bool doMethod(Square& other) { /* special case */ }
};
struct-Square;
结构三角形'
结构圆;
结构形状{
虚拟~Shape(){}
虚拟布尔圆顶法(方形和s){返回圆顶法(静态_投射);}
虚拟布尔圆顶法(三角形和s){返回圆顶法(静态_投射);}
虚拟布尔圆法{Circle&s){return圆法(static_cast);}
虚拟布尔方法(形状&)=0;
虚拟布尔myMethod(Shape&)=0;
};
结构三角形:形状{
boolmythod(Shape&other){返回other.doMethod(*this);}
bool-doMethod(形状和其他){/*一般情况*/}
布尔圆屋顶(方形和其他){/*特殊情况*/}
};

C++使用重载解析选择要调用的方法。重载解析完全基于参数的静态类型。如果被调用的重载是一个
虚拟
函数,则它可能在派生类中被重写,在这种情况下,调用在运行时被分派到重写

<> P>我可以说,你希望系统根据对象和参数类型来做多调度。C++不直接支持多分派,但是有一些方法可以模拟它。为了处理你想要的调度,可以安排你的调用在运行时找到合适的重写。这样做的一种方法是分割函数int。o多个版本

struct Square;
struct Triangle'
struct Circle;

struct Shape {
    virtual ~Shape() {}

    virtual bool doMethod(Square& s) { return doMethod(static_cast<Shape&>(s)); }
    virtual bool doMethod(Triangle& s) { return doMethod(static_cast<Shape&>(s)); }
    virtual bool doMethod{Circle& s) { return doMethod(static_cast<Shape&>(s)); }

    virtual bool doMethod(Shape&) = 0;
    virtual bool myMethod(Shape&) = 0;
};

struct Triangle: Shape {
    bool myMethod(Shape& other) { return other.doMethod(*this); }
    bool doMethod(Shape& other) { /* general case */ }
    bool doMethod(Square& other) { /* special case */ }
};
struct-Square;
结构三角形'
结构圆;
结构形状{
虚拟~Shape(){}
虚拟布尔圆顶法(方形和s){返回圆顶法(静态_投射);}
虚拟布尔圆顶法(三角形和s){返回圆顶法(静态_投射);}
虚拟布尔圆法{Circle&s){return圆法(static_cast);}
虚拟布尔方法(形状&)=0;
虚拟布尔myMethod(Shape&)=0;
};
结构三角形:形状{
boolmythod(Shape&other){返回other.doMethod(*this);}
bool-doMethod(形状和其他){/*一般情况*/}
布尔圆屋顶(方形和其他){/*特殊情况*/}
};

听起来像是访客模式的应用听起来像是访客模式的应用谢谢你的解释,这很有道理。但是你给出的代码让我在实现它时遇到了一些困难,因为形状实际上不知道正方形/三角形,因为它们继承自形状,所以我无法创建它们e虚拟方法。@Niamh:如果你不能向前声明需要特殊处理的形状,你需要一些其他方法来处理:哪一个最适合你的需要取决于你真正想要做什么。没有“好”的解决方案:所有这些都有其缺点:发布的一个需要了解类型(即,它是关闭的)但是它是有效的;其他方法以更大的灵活性换取效率。感谢您提供的信息,我已经了解了一些其他方法,并使用了一个简单的if语句if(Circle*cir=dynamic_cast(&aShape))如多重分派wiki页面所示。感谢您的解释,这是有意义的。但是,使用您提供的代码,我在实现它时遇到了一些困难,因为Shape实际上不知道正方形/三角形,因为它们是从Shape继承的,所以我无法创建这些虚拟方法。@Niamh:如果您不能向前声明也许需要特殊处理,你需要一些其他的方法来处理:哪一个最适合t