跨公共/受保护访问的基于const的函数重载

const-based function overloading accross public/protected access

本文关键字:函数 重载 const 访问 受保护      更新时间:2023-10-16

(我相信)我知道基于const重载函数:如果instant是const,则调用const方法,否则调用非常量方法。

示例(也在ideone):

#include <iostream>
struct S
{
void print() const { std::cout << "const method" <<std::endl };
void print()       { std::cout << "non-const method" <<std::endl };
};
int main()
{
S const s1;
s1.print(); // prints "const method"
S s2;
s2.print(); // prints "non-const method"
return 0;
};

我试图在代码中使用它,但当const重载的方法没有相同的访问类别时,遇到了一些问题。这可能是一种糟糕的风格,但这里有一个例子反映了返回引用以避免复制和使用const来限制意外更改的想法:

struct Color;
struct Shape
{
double area;
};
class Geometry
{
public:
// everybody can alter the color of the geometry, so 
// they get a mutable reference
Color& color() { return m_color; };
// not everybody can alter the shape of the Geometry, so
// they get a constant reference to the shape.
Shape const& shape() const { return m_shape; };
protected:
// derived classes can alter the shape, so they get 
// access to the mutable reference to alter the shape.
Shape & shape() { return m_shape; };
private:
Shape m_shape;
Color m_color;
};

我现在面临的问题是,如果其他函数扰乱了几何图形,比如按其区域为其着色,我希望编译器选择公共的const返回形状函数,为此需要访问几何图形的形状:

// this one fails
void colorByArea() {
for( Geometry g : geometryList )
{ g.color() = colorMap[g.shape().area]; }
}
// this one is a clunky workaround
void colorByArea() {
for( Geometry g : geometryList )
{ 
Geometry const& g_const = g;
g.color() = colorMap[g_const.shape().area];
}
}

这个(或类似的)失败了,出现了以下可以理解的错误:

‘Shape& Geometry::shape()’ is protected 
Shape & shape() { return m_shape; };
^ error: within this context
g.color() = colorMap[g.shape().area];

(我在ideone上举了一个稍微简化的非编译示例。)

我(在一定程度上)理解了为什么会发生这种情况:g不是const,因此应该调用protectec的non-const shape(),但这显然失败了。

所以我想我的问题是:如果一个非常量函数不可访问,有没有一种方法可以让常量函数"回退">

如果一个非常量函数不可访问,是否有一种方法可以对常量函数进行某种"回退">

否;过载解决发生在访问检查之前。

这不仅仅是糟糕的风格;这是糟糕的设计。公共getter函数在概念上与受保护函数不同,后者允许了解内部信息的代码修改对象的内部状态。通常,这两个函数甚至不需要具有相关的返回类型。因此,它们不应该有相同的名称。

您可以使用const_cast来允许将const版本调用为:

int main()
{
S s2;
const_cast<const S&>(s2).print(); // prints "const method"
return 0;
};

但是重命名其中一个方法会更好/更简单。