如何在C ++中创建Comparable接口并传递一系列可比对象?

皮卡杜

运行的代码示例:在此处在线运行此代码

我确实知道正确的完整示例应该使用模板类,但是为了简单起见,我希望看到一个没有模板的幼稚实现。

我还知道,<或>运算符的虚拟运算符重载在C ++中比多态的compareTo()方法签名更合适。

我也知道数组不是协变的,也不是协变的,我还是想看看这个例子在C ++中应该如何工作,我不想使用像vector这样的STL模板类型

我定义了抽象类(接口):

class Comparable {
    public:
    virtual int compareTo(Comparable *) = 0;
};

我有一个基类,与“可比”的概念无关

class Shape {
protected:    
    int width, height;
public:
    Shape(int a = 0, int b = 0)
    {
        width = a;
        height = b;
    }
    virtual int area() = 0;
};

我定义了一个形状后代矩形,它想成为一个可比较的:

class Rectangle : public Shape, public Comparable {

public:
    Rectangle(int a = 0, int b = 0) : Shape(a, b) {}

    virtual int compareTo(Comparable * other){
        return height - dynamic_cast<Rectangle *>(other)->height;
    } 

    int area()
    {
        return (width * height);
    }
};

测试方法和主程序:请参见test(...)方法中的注释。我在这里想念什么?

void test(Comparable* items[]){
    // tests polymorphic behavior. For example this would be a sort algorithm, 
    // which gets and array of comparables (array of pointers to Comparable)
    
    int result = items[0]->compareTo(items[1]);

    // result is 42 here, despite it is the meaning of life, is not appropriate. It is the area() method return value of items[0], instead of compareTo()
    // Debugging justifies, that not the compareTo method is called on the items[0] instance
    // instead the area() method... something is wrong with the cast... and not the correct method address used from the vtable ...
}

int main()
{
    Rectangle a(3,14), b(3,11);
    Rectangle* rectangles[2];
    rectangles[0] = &a;
    rectangles[1] = &b;

    // This is not good, but what would be the correct?
    test((Comparable **)rectangles);

    return 0;
}
o鸭

(Comparable **)rectangles您得到奇怪的结果,因为此强制转换是无效的reinterpret_cast。此无效的转换导致未定义的行为。在您的情况下,未定义的行为表示自己是在调用其他方法,而不是删除文件,因此很幸运。

C ++数组既不是协变也不是协变,特别是因为这样的强制转换不起作用。相反,您必须使用模板或进行复制:

int main()
{
    Rectangle a(3,14), b(3,11);
    Rectangle* rectangles[2];
    rectangles[0] = &a;
    rectangles[1] = &b;

    //See these changes here
    Comparable* comparables[2];
    comparables[0] = static_cast<Comparable*>(rectangles[0]);
    comparables[1] = static_cast<Comparable*>(rectangles[1]);
    test(comparables);

    return 0;
}

在幕后,它可能失败了,因为正常的实现是这样的:

ComparableVirtualTable class layout:
    int(*compareTo)(Comparable*);

Comparable class layout: 
    ComparableVirtualTable* comparableVirtualTable;

ShapeVirtualTable class layout: 
    int (*area)();

Shape class layout: 
    ShapeVirtualTable* shapeVirtualTable;
    int width;
    int height;

Rectangle class layout:
    //Contains Shape members
    ShapeVirtualTable* shapeVirtualTable;
    int width;
    int height;
    //followed by Comparable members
    ComparableVirtualTable* comparableVirtualTable;

值得注意的是:Shape成员和虚拟表位于Comparable虚拟表之前。因此,static_cast<Comparable>*(rectangles[...])实际上将返回指向的Comparable部分开始的指针Rectangle而不指向其Rectangle本身的开始这就是您(Comparable **)失败的原因,是它将Rectangle指针数组视为指针数组Comparable,但是指针没有指向Comparable数据成员!


旁注:所有带有virtual方法的也应virtual定义一个析构函数:virtual ~Comparable(){}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在python中给定列表的情况下创建一系列JSON对象?

如何在C ++中正确推回向量中的一系列对象?

如何在 C++11 中创建一系列索引的迭代器?

如何从一系列事件中创建日历?

如何从Android中的一系列图像创建视频?

如何在R中使用map遍历对象以创建一系列gt表

$ max如何在一系列对象上工作?

如何在umzug配置中传递一系列迁移实例

如何在TypeScript中优雅地初始化一系列对象?

您如何在Rails中创建一系列电子邮件?

如何在包含一系列日期的Postgres查询中创建临时表?

如何在python中创建一系列浮点值?

如何在CloudKit中查询由一系列用户创建的记录?

如何在pygame中制作一系列坐标?

如何在Django中迭代一系列功能?

如何在Rust中求和一系列数字?

如何在Excel中访问一系列行?

如何在JavaScript中检查一系列数字

如何在Ruby中替换一系列字符?

如何在R中过滤一系列数字?

如何在python中添加一系列数字

如何在一系列整数中除以a?

如何在ansible中循环一系列任务

如何创建一系列星期的系列?

如何在C#中获取一系列包含某些“价格”的XML元素

如何从对象中分离出一系列对象

如何遍历对象并匹配对象中一系列数字中的数字?

REDSHIFT:如何在redshift(Postgres 8.0.2)中创建一系列数字而不创建表“ numbers”?

如何使用一系列承诺在函数数组中传递参数