Const和非const访问解决了不同的重载?

时间:2010-10-13 08:44:50

标签: c++ design-patterns templates

让我说我们有一个简单的编程任务。但为了清楚起见,我从几个代码示例开始。 首先,我们编写了一些数据容器类,但无论类是什么,都是为了完成任务。我们只需要它表现为const-correct。

class DataComponent {
public:
    const std::string& getCaption() const {
        return caption;
    }

    void setCaption(const std::string& s) {
        caption = s;
    }

private:
    std::string caption;
};

然后让我们假设我们有一个类似 facade 的泛型类,而不是任意封装的类实例。假设我们重载了成员访问运算符(->)。

template <typename T> class Component {
public:
    Component() { instance = new T(); }

    ...

    const T* operator-> () const {
        return instance;
    }

    T* operator-> () {
        // but there might be additional magic
        return instance;
    }

private:
    T *instance;
};

此时我应该说我希望如何工作:

  • 如果我们通过成员访问运算符(component->setCaption("foo"))调用基础类的非const成员函数,则compilier会将非const T* operator-> ()视为最佳选择。
  • 否则,如果我们试图以相同的方式调用基础类的const成员函数(component->getCaption()),则编译器会选择const T* operator-> () const

上面的代码示例不会以这种方式工作,所以我很好奇为编译器提供类似于我提到的行为的可能性。任何命题。


编辑:让我们的成员访问运算符以这种方式重载:

    const T* operator-> () const { return instance; }

    T* operator-> () {
        cout << "something going change" << endl;
        return instance;
    }

让我们在某个地方有一个变量Component<DataComponent> c。然后在调用c->getCaption()时,stdout应该保持沉默,但是在调用c->setCaption("foo")时,stdout会警告我们某些事情会发生变化。 VS 2010 compilier让stdout在每次调用时警告我们。

我理解这种语义假设c同时表现为const和非const。但是我仍然在想着好奇心。

1 个答案:

答案 0 :(得分:3)

是否调用const或非const成员完全取决于调用它的对象的常量,而不是通过某些后续操作。在您考虑DataComponent中调用的特定方法之前,会做出该决定。您仍然可以使用DataComponent周围的代理对象直接破解所需的功能,const和非const转发getCaption()

编辑:请求的详细信息(在我的头顶)。你需要转发声明这些东西 - 我没有打扰因为它让它更加混乱。切入任何问题/反馈。请注意,这基本上假设您不能/不想出于某种原因修改Component,但它不是一个通用的模板化解决方案,它可以简单地包含在任意类型中 - 它非常重合并且具有很高的维护负担。 / p>

// know they can't call a non-const operation on T, so this is ok...
const T* Component::operator->() const { return instance; }

// they might invoke a non-const operation on T, so...
DataComponent::Proxy Component::operator->() { return DataComponent.getProxy(*this); }
class DataComponent中的

struct Proxy
{
    Component& c_;
    DataComponent& d_;

    Proxy(Component& c, DataComponent& d) : c_(c), d_(d) { }

    const std::string& get_caption() const { return d_.get_caption(); }

    void set_caption(const std::string& s)
    {
        c_.on_pre_mutator(d_);
        d_.set_caption(s);
        c_.on_post_mutator(d_);
    }
};

然后

DataComponent::Proxy DataComponent::getProxy(Component& c) { return Proxy(c, *this); }

所以,这意味着您需要手动编写转发函数。这是一个痛苦,但如果你这样做是为了调试或测试它并不是不合理的。如果你这样做,你可以添加一个锁或什么,那么可能有更好的选择。