如何在 const 成员函数中使用非常量成员函数?

Posted

技术标签:

【中文标题】如何在 const 成员函数中使用非常量成员函数?【英文标题】:How to use a non-const member function inside a const member function? 【发布时间】:2016-05-26 08:10:09 【问题描述】:

以下是一个简单的 C++ 结构和一个用于 3D 向量和 3x3 矩阵的类。如您所见,下标运算符对它们都进行了重载。我从它们返回对数据成员的引用,以便能够分配给vec[0] = 5.0;mat[0] = vec3(2.0);mat[0][0] = 3.0; 等成员。现在我为mat3 声明另一个运算符,加号(+)运算符它不应该修改矩阵本身,但应该返回一个新矩阵作为总和。如何使这个非修改 + 运算符成为const

矢量

struct vec3 
    typedef double value_type;
    vec3::value_type x, y, z;

    vec3(const vec3::value_type x,
         const vec3::value_type y,
         const vec3::value_type z)
    : xx, yy, zz 

    vec3(const vec3::value_type w)
    : vec3(w, w, w) 

    vec3()
    : vec3(0.0) 

    // this works because [] operator is not used
    vec3 operator+(const vec3& v) const 
        return vec3(this->x + v.x, this->y + v.y, this->z + v.z);
    

    vec3::value_type& operator[](const std::size_t index) 
        switch(index) 
        case 0:
            return x;
        case 1:
            return y;
        case 2:
            return z;
        default:
            throw std::invalid_argument("vec3 supports upto 3(0-2) elements");
        
    
;

矩阵

class mat3 
    std::array<vec3,3> val;
public:
    using vtype = vec3::value_type;
    mat3(const vtype v00, const vtype v01, const vtype v02,
         const vtype v10, const vtype v11, const vtype v12,
         const vtype v20, const vtype v21, const vtype v22) 
        val[0][0] = v00; val[0][1] = v10; val[0][2] = v20;
        val[1][0] = v01; val[1][1] = v11; val[1][2] = v21;
        val[2][0] = v02; val[2][1] = v21; val[2][2] = v22;
    

    mat3(const vtype m[3][3]) 
        for(std::size_t i = 0; i < 3; ++i) 
            for(std::size_t j = 0; j < 3; ++j) 
                val[i][j] = m[j][i];
            
        
    

    mat3(const vtype v)
    : mat3(v, v, v,
           v, v, v,
           v, v, v) 

    mat3()
    : mat3(0.0) 

    // how to make it `const`
    mat3 operator+(const mat3& m) 
        mat3 t;
        for(std::size_t i = 0; i < 3; ++i) 
            t[i] = val[i] + m[i];
        
        return std::move(t);
    

    vec3& operator[](const std::size_t index) 
        switch(index) 
        case 0:
            return val[0];
        case 1:
            return val[1];
        case 2:
            return val[2];
        default:
            throw std::invalid_argument("mat3 supports upto 3(0-2) vec3");
        
    
;

【问题讨论】:

您没有提供const 版本的operator [] 是否有特殊原因? (老实说,对于这两个,但对于vec3,至少)。 @WhozCraig 我不知道除了这个之外还可以添加另一个 const 版本。 你还没有 const 版本,所以不涉及“another”和“besides”;只有“除了”,是的,你可以。 是的,another 想表示这个运算符的另一个版本,我认为只有参数类型在重载中才重要,而不是返回类型,现在很清楚了。 return std::move(t); 应该是 return t;。这已经是一个移动上下文,你的版本禁止 NRVO 【参考方案1】:

您可以(并且应该)为operator[] 添加一个常量版本,然后您可以将operator+ 设为常量,operator[] 的常量版本将在其中被调用。

vec3& operator[](const std::size_t index) 
    ...

const vec3& operator[](const std::size_t index) const 
~~~~~                                           ~~~~~
    ...

请注意,您可以重载 const 和非 const 成员函数。

见const-, volatile-, and ref-qualified member functions(强调我的)

非静态成员函数可以用constvolatile、 或 const volatile 限定符(此限定符出现在 函数声明中的函数)。 不同的 cv 合格 函数具有不同的类型,因此可能会相互重载。

在 cv 限定函数的主体中,this 指针是 cv 合格,例如在一个 const 成员函数中,只有其他 const 成员 函数可以正常调用。 (非常量成员函数可以 如果应用const_cast 或通过访问路径仍会调用 不涉及this。)

【讨论】:

等等我能做到吗?重载不只考虑参数类型吗? @Samik 是的,你可以,const 和非 const 成员函数确实很重要,有一个不同类型的隐式 this @Samik 也许已经很清楚了,但无论如何:是的,只有参数类型必须不同,因此您不能在已有的 const vec3&amp; operator[](const std::size_t index) 旁边声明另一个。但是 const vec3&amp; operator[](const std::size_t index) const 采用不同的参数(它必须是 const) @tobi303 是的,你是对的。可能是成员函数的constness 决定了隐式this 指针的constness,正如宋元耀所说。 @Samik 是的,当我写“采用不同的参数”时,我实际上指的是隐含的 this 参数

以上是关于如何在 const 成员函数中使用非常量成员函数?的主要内容,如果未能解决你的问题,请参考以下文章

测试页面

定义非常量“get”成员函数的原因?

const 成员函数的重载解析 C++

C++Primer 第七章

虚函数后面的const=0

RAII:在 const 方法中初始化数据成员