【问题标题】:Const operator overloading problems in C++C++ 中的 const 运算符重载问题
【发布时间】:2011-01-27 07:05:32
【问题描述】:

我在使用 const 版本重载 operator() 时遇到问题:

#include <iostream>
#include <vector>
using namespace std;

class Matrix {
public:
    Matrix(int m, int n) { 
        vector<double> tmp(m, 0.0);
        data.resize(n, tmp);
    }
    ~Matrix() { }


    const double & operator()(int ii, int jj) const {
        cout << " - const-version was called - ";
        return data[ii][jj];
    }

    double & operator()(int ii, int jj) {
        cout << " - NONconst-version was called - ";
        if (ii!=1) {
            throw "Error: you may only alter the first row of the matrix.";
        }
        return data[ii][jj];
     }


protected:  
    vector< vector<double> > data;
};

int main() {
try {
    Matrix A(10,10);
    A(1,1) = 8.8;
    cout << "A(1,1)=" << A(1,1) << endl;
    cout << "A(2,2)=" << A(2,2) << endl;
    double tmp = A(3,3);
} catch (const char* c) { cout << c << endl; }
}

这给了我以下输出:

  • NONconst-version 被调用 - - NONconst-version 被调用 - A(1,1)=8.8
  • 调用了 NONconst-version - 错误:您只能更改矩阵的第一行。

如何实现 C++ 调用 operator() 的 const 版本?我正在使用 GCC 4.4.0。

【问题讨论】:

  • 我希望能够修改我的矩阵条目,但只有一些。

标签: c++ operators constants conversion-operator


【解决方案1】:

重载看起来不错,但你永远不会在 const 对象上调用它。你可以试试这个:

void foo(const Matrix& A) {
  cout << "A(1,1)=" << A(1,1) << endl;
}

Matrix A(10,10);
foo(A);

这给了你:

 - const-version was called - A(1,1)=0

【讨论】:

  • 谢谢!在我看来,不幸的是,即使在非常量对象上,C++ 也不会“默认”调用 c​​onst 方法。我会把它放在愿望清单上。
  • 如果是这样,什么时候会调用非常量方法?您总是可以删除非常量重载,它甚至会在非常量对象上调用 const 。
  • 当需要执行非常量操作时会调用。是的,我可以删除非常量重载方法,但因为我有时也想为矩阵元素分配一些东西,从而减少功能。感谢您的建议。
【解决方案2】:

你调用方法的对象必须是const,例如

cout << "A(2,2)=" << (*static_cast<const Matrix*>(&A))(2,2) << endl;

【讨论】:

  • 嗯,这与我想使用该运算符的“使用简单”范式相矛盾...
  • 好吧,这几乎是没有必要的;您的 const 和非 const 版本在行为上应该非常接近,除了可能为您调整容器大小的非常量版本之外。如果您在两个版本中执行的操作完全不同,需要在它们之间进行转换,请考虑使用不同的方法。
  • 我想将这个用于带状矩阵,只有当我靠近矩阵的对角线时我才能调用非常量运算符()(否则元素不会存储并且隐式为零,所以操作员需要抛出一个错误)。我现在会做不同的方法。
  • 这就是const_cast&lt;&gt; 的用途。编辑 - 你不应该对指针做任何事情。
  • @James - 我不同意; const_cast 比 static_casts 更强大(或者我更喜欢的一个,目前不是标准的implicit_cast),并且不应该使用像添加 constness 这样的安全操作。在代码中看到 const_cast 意味着存在很大的设计缺陷;使用它来添加 constness 严重地淡化了这个含义。
【解决方案3】:

通常,您不能调用函数的 const 或非 const 版本,具体取决于您对返回值的处理方式。如果您想模拟类似的功能,您可以尝试返回一些代理,该代理将根据您使用它的方式切换行为:

class Proxy
{
  Matrix& m;
  int x, y;
public:
  ...
// mutating operations
  operator double&() { check(); return m.index(x,y); }
  double& operator=(double d) { check(); return m.index(x,y)=d; }
// ... other mutating operations (+=, ...) analogously

// nonmutating ops
  operator double() { return m.const_index(x, y); }
  operator const double&() // ... same
};

Proxy Matrix::operator(int x, int y)
{
  return Proxy(*this, x, y);
}

假设check() 是您对合法突变的检查(可以集成在index() 中)并且index()const_index() 是Matrix 中的方法,它们提供对特定位置的引用或const 引用。

【讨论】:

  • 好的,进阶的……会考虑的:-)
  • 其实这样编译不了:operator double() { return m.const_index(x, y); } operator const double&() 而此编译在第二行末尾添加 const: operator double() { return m.const_index(x, y); };运算符 const double&() const;
【解决方案4】:

使用 const_cast() 或将您的实例设为 const。

我猜你可能想确保操作符返回一个 const double?也许你应该只提供 const 版本,而不是另一个。

【讨论】:

    【解决方案5】:

    你有不同的方法和不同的功能,所以给他们不同的名字。那么你不需要有一个 const 对象来调用你想要的。

    你仍然可以让operator() const 调用替代函数,以防你发生有一个 const 对象。但替代功能应放在具有描述性名称的函数中。

    至于获取对象的const 句柄,请使用static_cast&lt; const Matrix &amp; &gt;( A )

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      相关资源
      最近更新 更多