将基类的对象传递给派生类的引用函数

Posted

技术标签:

【中文标题】将基类的对象传递给派生类的引用函数【英文标题】:Passing object of base class to function of reference to derived class 【发布时间】:2020-10-08 15:41:19 【问题描述】:

我正在尝试编写可以找到许多不同类型形状之间距离的代码。我已经定义了一个基类Shape 和一个virtual distance(Shape& otherShape) 函数来查找到另一个形状的距离,然后想为我的所有派生类定义它。

问题是有很多可能的形状对,所以我的解决方案是在类之外定义一组距离函数(圆-圆、圆-正方形、正方形-三等),然后调用相应的一是距离函数。我在下面添加了一个迷你示例,其中只有一个派生类 Circle 来演示问题。

当我尝试调用我的特定 circleCircleDistance 函数时,我收到一个错误,因为它无法将基类转换为派生类。有什么办法可以解决这个问题,或者我的设计是否行不通?

enum ShapeTypeCIRCLE, SQUARE;

class Shape 
public:
    ShapeType type;
    virtual double distance(Shape& otherShape) = 0;
;

class Circle : public Shape 
public:
    ShapeType type = CIRCLE;
    double distance(Shape& otherShape) override;
;


double circleCircleDistance(Circle& circle1, Circle& cirlce2)
    return 0; //pretend this does the calculation
;

double Circle::distance(Shape &otherShape) 
    switch (otherShape.type)
        case CIRCLE:
            //Here I get the error
            //cannot bind base class object of type Shape to derived class reference Circle& for 2nd argument
            return circleCircleDistance(*this, otherShape);
            
    

【问题讨论】:

【参考方案1】:

您必须将 Shape& 转换为 Circle&

return circleCircleDistance(*this, static_cast<Circle&>(otherShape));

顺便说一句,我会以不同的方式处理您的类型

class Shape 
public:
    virtual ShapeType get_type() const = 0;  // derived classes must override this
    virtual double distance(Shape& otherShape) = 0;
;

class Circle : public Shape 
public:
    ShapeType get_type() const override  return CIRCLE;  // here's your override
    double distance(Shape& otherShape) override;
;

...

   switch (otherShape.get_type())

否则,您将遇到type 从派生类/基类中隐藏的情况,具体取决于您访问它的方式。

【讨论】:

哦,当然!谢谢,我试过这个,但要投到 Circle 而不是 Circle&!也感谢您提供有关类型的提示!【参考方案2】:

C++ 本身不支持多分派。 多亏了虚拟方法,我们只有一次调度。

因此您可以为您的案例实施double dispatch。

一个(C++17)“替代”选项是使用std::variant,它具有实现多个调度的std::visit

您可以保留或删除它。

struct Circle 
    Point center;
    float radius;
;

struct Rectangle 
    Point topLeft;
    Point bottomRight
;

using Shape = std::variant<Square, Rectangle>;

double distance(const Square&, const Square&);
double distance(const Square&, const Rectangle&);
double distance(const Rectangle&, const Square&);
double distance(const Rectangle&, const Rectangle&);

double distance(const Shape& shape1, const Shape& shape2)

    return std::visit([](const auto& shape1, const auto& shape2)
                           return distance(shape1, shape2);
                      ,
                      shape1,
                      shape2);


【讨论】:

好的,谢谢,这似乎是一个有趣的想法,我会研究一下。我看到的一个问题是必须定义 A-B 和 B-A,但我想一旦你有了一个,另一个很容易只需调用交换参数的函数。 在您的试探中,您也必须处理 A-B 和 B-A。因为它确实是对称的,所以一个可以调用另一个,但是这个问题无论如何与多次调度无关。 是的,我想是的,我只需要例如一个 circleSquareDistance 函数,但需要以正确的顺序处理 Circle 和 Square 类中的情况。【参考方案3】:

在 c++20 中,您可以使用带有概念的模板专业化来解决此类问题

【讨论】:

以上是关于将基类的对象传递给派生类的引用函数的主要内容,如果未能解决你的问题,请参考以下文章

虚函数总结

将基类转换为派生类[重复]

检测基类对指向派生类的引用的分配

我们可以将基类的私有成员继承到派生类的公共成员中吗?

关于C++基类、派生类的引用和指针

无法将参数 1 从派生指针转换为基类指针引用