使用constness修改重载成员操作符

Modifying overloaded member operator using constness

本文关键字:成员 操作符 重载 修改 constness 使用      更新时间:2023-10-16

我的问题概述如下:我有一个名为TWMatrix的模板化类。我已经重载了()运算符,这样它就可以接受一对TWMatrix并提取相应的条目。我希望"提取"在两个不同的情况下产生两个不同的结果。当取一对int型时,这之前已经工作了,但是对于这个稍微不同的问题,我很难让它工作:

  • 在一种情况下,我希望操作符将条目复制到另一个TWMatrix中并输出。
  • 在另一种情况下,我希望操作符将这些条目的地址复制到TWDataPointer类型的对象中,并输出该对象。

在第一种情况下,该方法不破坏constness。事实上,这些条目本身既没有被修改,也不会受到将来修改的影响。在后一种情况下,关键在于TWDataPointer对象可以用来修改矩阵的那些条目。对应的位码是:

TWDataPointer<T> operator () (const TWMatrix<int> & I1, const TWMatrix<int> & I2)
{
     return TWDataPointer<T>(*this,I1,I2);
}
TWMatrix<T> operator () (const TWMatrix<int> & I1, const TWMatrix<int> & I2) const 
{
    return SubMat(I1,I2);
}

SubMat是一个创建具有相应条目的矩阵的方法。它工作得很好,它获取的值在这里不是很重要。问题是,第二个操作符似乎永远不会被调用。例如,在main中,我写:

TWMatrix<double> test = D5(I1,I2);

编译器报错说:

error: conversion from ‘TWDataPointer<double>’ to non-scalar type ‘TWMatrix<double>’ requested

T operator () (const int & i, const int & j) const 
{
    return data[j+i*nc];
}
T& operator () (const int & i, const int & j) 
{
    return data[j+i*nc];
}

完全按照预期工作,并返回T或T&视情况而定。从我对重载操作符的理解来看,是const让编译器区分在什么情况下使用哪个操作符。那么,为什么这行不通呢?

提前感谢您的帮助,并随时要求您可能需要的任何额外的代码片段。

PS:我已经有了一个解决这个问题的方法,虽然它不是非常丑陋,但它远没有这样简单,优雅和健壮,如果我能让它工作的话。

谢谢到目前为止的帮助,我仍然期待听到你的答案。特别是,我仍然对这个感到困惑:

"回到int的例子,为什么a = test(0,0)使用相应操作符的const版本,即使test没有声明为const?实际上,我在两个版本的()操作符中使用cout语句检查了这种情况。"

是否有一个特定的原因,您只需要第二个方法的单个const ?从这段代码和可能的使用场景来看,虽然您的第二个方法在技术上是const方法,但它没有要这样声明。换句话说,它是一个可以被const和非const版本的类实例使用的方法,你显然会遇到这样的情况,你的类实例需要的方法,当它不是一个const对象。因此,将方法标记为const方法只是因为它不会改变调用该方法的实例的状态,并不意味着您必须将方法标记为const

为了处理这两种情况,我将生成两个版本的operator(),返回TWMatrix<T>类型…一个被声明为const,另一个被声明为非const方法,以便const和非const类实例都可以使用它。缺点是你必须创建一个单独的方法来返回TWDataPointer<T>类型,因为你不能仅仅基于返回类型重载。

猜测,这是因为D5不是常数。该对象的cv-限定符决定选择哪个操作符。

看起来您正在使用const限定符来消除运算符的歧义。我会使用一种不同的技术(例如,模板参数是你想要的输出类型,或者模板参数是定义如何构造返回类型的策略,或者更简单,指定你想要的输出参数)

用于非静态成员函数。有一个隐含的对象参数——this指针。如果将非静态成员函数声明为const,则this指针将是const。实际上,你的两个函数看起来像:

TWDataPointer<T> operator () (this, const TWMatrix<int> & I1, const TWMatrix<int> & I2)
{
     return TWDataPointer<T>(*this,I1,I2);
}
TWMatrix<T> operator () (const this, const TWMatrix<int> & I1, const TWMatrix<int> & I2) const 
{
    return SubMat(I1,I2);
}

我认为现在很清楚,为什么当你的D5不是const时,第二个函数永远不会被调用。你可以使用

TWMatrix<T> matrix = ((const TWMatrix<T>&)D5)(I1,I2);

作为变通方法。但我不认为这是个好主意。const和非const方法得到不同的结果类型是非常棘手的。

对于int的例子,如果测试不是const,我不认为第一个函数会被调用