读书人

有关引用符号和常对象的有关问题

发布时间: 2012-02-14 19:19:19 作者: rapoo

有关引用符号和常对象的问题
最近在学习《Essential C++》时遇到了一个有关类中声明const与非const成员函数重载的问题(P111页),源程序如下:

class val_calss{
public:
val_class(const Bigclass &v)
:_val(v){} //用成员初值表进行构造

BigClass& val() const {return _val;}
//此处产生问题,返回一个non-const的引用指向_val,实际上等于将_val开放出去,破坏了val_class 的封装性

private:
BigClass _val;
};

书中为解决上述问题采用了重载成员函数的做法(定义一份const版本和non-const版本的函数):

class val_class{
public:
const BigClass& val() const {return _val;}
BigClass& val() {return _val;}
//...
};

我的问题在于:第二个函数定义时依然使用了引用符号(&)定义返回值类型,这样怎能达到保护成员变量的目的呢?

另外,书后又写:“设计Class时,鉴定其const member functions是一件很重要的事。如果你忘了这么做,要知道,没有一个const reference class参数可以调用公开接口中的non-const部分。用户也许会因此大声咒骂。将const加到class内并非易事,特别是如果某个member function被广泛使用之后。”关于这点我也不能完全理解。
请各位多加指点!

[解决办法]
先来段代码, VS2003下可以编译, 这里用long模拟你的BigClass, 100l后面的小L表示它是个long

// test.cpp
// cl -EHsc test.cpp

#include <iostream>

class val_class {
public:
explicit val_class(long value) : value_(value) { }
long const & val() const { return value_; }
long & val() { return value_; }
private:
long value_;
};

// !! 这个可以改
void set_value() {
val_class v(100l);
v.val() = 1000l;
std::cout < < "set_value - value_.val() = " < < v.val() < < std::endl;
}

class access_value {
public:
access_value() : value_(100l) { }
void non_const_set() {
value_.val() = 1000l;
std::cout < < "access_value::non_const_set - value_.val() = " < < value_.val() < < std::endl;
}
//void const_set() const { // 这个就编译不通过
// value_.val() = 1100l;
// std::cout < < value_.val() < < std::endl;
//}
private:
val_class value_;
};

int main() {
set_value();

access_value av;
av.non_const_set();
}

正如你所尝试的.const BigClass& val() const {return _val;} 这个版本的val方法, 将在调用方是一个const版本的方法中,被编译器检测出来. 也就是说, 它要依赖, 你项目中的所有类设计都严格按照 良好的选择 const或非const 及 双版才能发挥效力.

而对于普通函数, 非const版成员方法, 也是防不住的.
[解决办法]
一个一个的来回答你的问题:

BigClass& val() const {return _val;}
//此处产生问题,返回一个non-const的引用指向_val,实际上等于将_val开放出去,破坏了val_class 的封装性

这里返回的_val是这个类的私有成员,而现在返回的是这个成员的引用,那么在类外调用这个函数BigClass& val()的时候,会将_val本身返回到类外,在类外就可以对它进行修改,这样破坏了类的封装性.

例如:
BigClass& change=BigClass& val(); //现在change就是类内的_val
//do something to change //这就相当于修改了类内的_val


[解决办法]
BigClass& val() {return _val;}
这种保证不了成员变量不被修改,
你是不是写错了,应该是:
BigClass val() {return _val;} //按值返回

如果是按值返回的话,返回的当然是一个副本,对它的修改不影响成员变量本身
[解决办法]
应该这样吧
BigClass val(){return _val;} //按值返回
这样就不会被修改了。
const BigClass& val() const {return _val;}的话是const常量,修改编译器会报错。个人觉得这样写不妥~

读书人网 >C++

热点推荐