c++ 避免返回内部数据的句柄

为什么const对象只能访问const成员函数

C Primer中说了,在一个对象调用其成员函数时,它隐含的一个形参this指针。
例如,我们定义了一个函数CTest::ttt();实际上在编译器中该函数的定义就是CTest::ttt(CTest *const
this),该this指针所指向的内容可以改变,但是该this指针不可以被改变。当我们用CTest的一个对象test1调用ttt函数时即test1.ttt()时,编译器就会将它解释为ttt(&test1),所以我们在ttt中使用this指针就可以改变对象test1的成员变量了。
但是,当我们的对象是const对象时,即const CTest ttt;这时候表示什么意思呢,ttt的内容是不可以改边的,当我们把&ttt作为一个参数传到形参this时,矛盾出现了:ttt是一个常量,其成员不可以被改变;this指针的成员变量是可以改变的。如果我能正确的将ttt的地址传给this,那么ttt这个常量的值不是可以在this中被改变了吗,所以,编译器是不允许这种情况出现的,就提示错误了。故const对象不能访问非const成员函数。
同理,当我们的成员函数是const成员函数时,例:CTest::ttt() const,在编译器解释时会将该函数解释为CTest::ttt(const CTest * const this),this指针及其所指向的内容都不可以被修改,前面提到的矛盾也就不存在了,所以const对象可以访问const成员变量。

总结一下如下两表:
对象.成员函数

对象成员函数是否可行
constconst
constnon-const
non-constconst
non-constnon-const

成员函数调用成员函数

成员函数成员函数是否可行
constconst
constnon-const
non-constconst
non-constnon-const

篡改const对象

class String1
{
public:
    String1 (const char *value)
    {
        data = new char[strlen(value)+1];

        strcpy(data,value);
    }
    ~String1(){delete data;}
    operator char *() const 
    {
        return data;
    }
    void getdata() const   // 需要加上const  不然会提示错误对象包含与成员函数不兼容的类型限定符
    {
        cout<< data;
    }

private:
    char *data;
};

这个时候我们可以

    const String1 B("HELLO");
    String1 & alsoB=const_cast<String1&>(B);
    char *str=B;
    str[1]='e';  // 这样就篡改了一个const对象里的数据了。。。
    B.getdata();

所以我们operator的代码需要更改

operator const char *() const 
{
        return data;
}

这样我们

const char *str=B;   //只能这样了。。
    //str[1]='e';     //此时就不能更改了

指针并不是返回内部数据句柄的唯一途径。引用也很容易被滥用。下面是一种常见的用法,还是拿 String 类做例子:

class String2 
{
public:
    String2 (const char *value)
    {
        data = new char[strlen(value)+1];

        strcpy(data,value);
    }
     operator const char *() const 
    {
        return data;
    }
      void getdata() const   // 需要加上const  不然会提示错误对象包含与成员函数不兼容的类型限定符
    {
        cout<< data;
    }
  char& operator[](int index) const  // 不加引用是不能赋值的~
      { return data[index]; }
private:
  char *data;
};

这样也可以修改s。。。

const  String2 s = "I'm not constant"; 

    s[0]='x';

这类问题的通用解决方案和前面关于指针的讨论一样:或者使函数为非 const,或者重写函数,使之不返回句柄。 并不是只有 const 成员函数需要担心返回句柄的问题,即使是非 const 成 员函数也得承认:句柄的合法性失效的时间和它所对应的对象是完全相同的。 这个时间可能比用户期望的要早很多,特别是当涉及的对象是由编译器产生的临时对象时。

所以,对于 const 成员函数来说,返回句柄是不明智的,因为它会破坏数据抽象。对于非 const 成员函数来说,返回句柄会带来麻烦,特别是涉及到临 时对象时。句柄就象指针一样,可以是悬浮(dangle)的。所以一定要象避免 悬浮的指针那样,尽量避免悬浮的句柄。
例如:

 String2 some()
{
    return "asdf";
}
............
const char *p = some();
    cout<<p;

因为当你想打印 pc 所指的字符串时,字符串的值是不确定的。造 成这一结果的原因在于 pc 初始化时发生了下面这些事件: 1. 产生一个临时
String 对象用以保存 someFamousAuthor的返回值。 2. 通过 String 的 operator const
char*成员函数将临时 String 对象转换为 const char*指针,并用这个指针初始化 pc。 3. 临时 String
对象被销毁,其析构函数被调用。析构函数中,data 指针被删除 (代码详见条款 11)。然而,data 和 pc
所指的是同一块内存,所以现在 pc 指 向的是被删除的内存——–其内容是不可确定的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值