让我说我们有一个简单的编程任务。但为了清楚起见,我从几个代码示例开始。 首先,我们编写了一些数据容器类,但无论类是什么,都是为了完成任务。我们只需要它表现为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-> ()
视为最佳选择。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。但是我仍然在想着好奇心。
答案 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); }
所以,这意味着您需要手动编写转发函数。这是一个痛苦,但如果你这样做是为了调试或测试它并不是不合理的。如果你这样做,你可以添加一个锁或什么,那么可能有更好的选择。