effective c++相关关键字

本文深入探讨了C++中const成员函数的概念意义、bitwiseconstness与conceptualconstness的区别,并通过实例展示了如何在成员函数中安全地处理const对象,包括使用mutable关键字、局部指针及避免滥用const强制转换的方法。此外,文章还阐述了类型转换函数的定义及其在将类对象转换为其他类型时的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(1)关于const类型的函数,也就是在函数名后面加一个const

一个成员函数为const的确切含义是什么?有两种主要的看法:数据意义上的const(bitwise constness)和概念意义上的const(conceptual constness)。
bitwise constness的坚持者认为,当且仅当成员函数不修改对象的任何数据成员(静态数据成员除外)时,即不修改对象中任何一个比特(bit)时,这个成员函数才是const的。bitwise constness最大的好处是可以很容易地检测到违反bitwise constness规定的事件:编译器只用去寻找有无对数据成员的赋值就可以了。实际上,bitwise constness正是c++对const问题的定义,const成员函数不被允许修改它所在对象的任何一个数据成员。

不幸的是,很多不遵守bitwise constness定义的成员函数也可以通过bitwise测试。特别是,一个“修改了指针所指向的数据”的成员函数,其行为显然违反了bitwise constness定义,但如果对象中仅包含这个指针,这个函数也是bitwise const的,编译时会通过。这就和我们的直觉有差异:
class string {

 public:

          // 构造函数,使data指向一个 // value所指向的数据的拷贝

            string(const char *value);
          ...
           operator char *() const { return data;}
private:

      char *data;

 };
const string s = "hello"; // 声明常量对象
char *nasty = s; // 调用 operator char*() const
*nasty = 'm'; // 修改s.data[0]
cout << s; // 输出"mello"
显然,在用一个值创建一个常量对象并调用对象的const成员函数时一定有什么错误,对象的值竟然可以修改!(关于这个例子更详细的讨论参见条款29)
这就导致conceptual constness观点的引入。此观点的坚持者认为,一个const成员函数可以修改它所在对象的一些数据(bits) ,但只有在用户不会发觉的情况下。例如,假设string类想保存对象每次被请求时数据的长度:
class string {

public:

        // 构造函数,使data指向一个 // value所指向的数据的拷贝

        string(const char *value): lengthisvalid(false) { ... }
       ...
       size_t length() const;
private:

     char *data;
     size_t datalength; // 最后计算出的 // string的长度
     bool lengthisvalid; // 长度当前 // 是否合法};
     size_t string::length() const

     {

              if (!lengthisvalid)

              {

                  datalength = strlen(data); // 错误!

                 lengthisvalid = true; // 错误!

            }
           return datalength;

     }
这个length的实现显然不符合“bitwise const”的定义——datalength 和lengthisvalid都可以修改——但对const string对象来说,似乎它一定要是合法的才行。但编译器也不同意, 它们坚持“bitwise constness”,怎么办?
解决方案很简单:利用c++标准组织针对这类情况专门提供的有关const问题的另一个可选方案。此方案使用了关键字mutable,当对非静态数据成员运用mutable时,这些成员的“bitwise constness”限制就被解除:
class string {

 public:
... // same as above
private:

 char *data;
mutable size_t datalength; // 这些数据成员现在 // 为mutable;他们可以在

mutable bool lengthisvalid; // 任何地方被修改,即使 // 在const成员函数里

};

    size_t string::length() const

    {

             if (!lengthisvalid)

             {

                     datalength = strlen(data); // 现在合法

                    lengthisvalid = true; // 同样合法

            }
         return datalength;

  }
mutable在处理“bitwise-constness限制”问题时是一个很好的方案,但它被加入到c++标准中的时间不长,所以有的编译器可能还不支持它。如果是这样,就不得不倒退到c++黑暗的旧时代去,在那儿,生活很简陋,const有时可能会被抛弃。
类c的一个成员函数中,this指针就好象经过如下的声明:
c * const this; // 非const成员函数中
const c * const this; // const成员函数中
这种情况下(即编译器不支持mutable的情况下),如果想使那个有问题的string::length版本对const和非const对象都合法,就只有把this的类型从const c * const改成c * const。不能直接这么做,但可以通过初始化一个局部变量指针,使之指向this所指的同一个对象来间接实现。然后,就可以通过这个局部指针来访问你想修改的成员:
size_t string::length() const { // 定义一个不指向const对象的 // 局部版本的this指针 string * const localthis = const_cast<string * const>(this);
if (!lengthisvalid) { localthis->datalength = strlen(data); localthis->lengthisvalid = true; }
return datalength; }
做的不是很漂亮。但为了完成想要的功能也就只有这么做。
当然,如果不能保证这个方法一定可行,就不要这么做:比如,一些老的“消除const”的方法就不行。特别是,如果this所指的对象真的是const,即,在定义时被声明为const,那么,“消除const”就会导致不可确定的后果。所以,如果想在成员函数中通过转换消除const,就最好先确信你要转换的对象最初没有被定义为const。
还有一种情况下,通过类型转换消除const会既有用又安全。这就是:将一个const对象传递到一个取非const参数的函数中,同时你又知道参数不会在函数内部被修改的情况时。第二个条件很重要,因为对一个只会被读的对象(不会被写)消除const永远是安全的,即使那个对象最初曾被定义为const。
例如,已经知道有些库不正确地声明了象下面这样的strlen函数:
size_t strlen(char *s);
strlen当然不会去修改s所指的数据——至少我一辈子没看见过。但因为有了这个声明,对一个const char *类型的指针调用这个函数时就会不合法。为解决这个问题,可以在给strlen传参数时安全地把这个指针的const强制转换掉:
const char *klingongreeting = "nuqneh"; // "nuqneh"即"hello" // size_t length = strlen(const_cast<char*>(klingongreeting));
但不要滥用这个方法。只有在被调用的函数(比如本例中的strlen)不会修改它的参数所指的数据时,才能保证它可以正常工作。

 

 

(2)

 

谁帮我分析下这句话operator const char *() const谢谢

网上有人说是()的重载  是这样的吗  谁能帮我具体分析下这句话  说下怎么用  谢谢

问题补充:

有人说的是括号的重载() 然后拷贝对象用的  我晕掉了啊  怎么解释啊  要是能把这个函数补全就最好不过了  谢谢
答案:
一楼简直是乱讲!如果是重载*的话,那应该写成:const char operator * () const而不是楼主所写的那样,而且即使是这样写那也不正确的,因为运算符重载中有几个运算符的返回值是有格式的(约定),如operator * 在重载时通常返回值是classType&或者const classType& 。
operator const char*() const是类型转换函数的定义,即该类型可以自动转换为const char*类型。至于最后一个const,那个大家都知道是对类成员的限制(不允许更改对象的状态)
虽然我不知道你的类是什么,但是我可以给你举一个简单的例子说明一下问题。比如我们现在自定一个一个整型(MyInt),它允许在需要使用C++语言中的int类型时将MyInt类型转换为int类型:
class MyInt {
     public:
          operator int () const;
     private:
          int elem;
};
MyInt::operator int () const
{
    return elem;
}
就可以在需要使用int类型时使用MyInt。
还有你需要记住,C++中没有返回类型的函数有3个,构造函数、析构函数、类型转换函数。前两个是不写返回类型函数实现中也不允许出现return语句(所以不同于void),
最后一个则是不写返回类型,但是必须返回对应类型的值,即必须出现return语句。
 
(3)//此函数会调用两次拷贝构造函数,首先对象转为s对象,s转为返回对象
student returnstudent(student s) 
{ return s; 
}
  C++把pass-by-value作为缺省行为,这是为了沿袭C的传统。函数参数都是以实参的副本(就是以传入参数为本,调用copy constructor返回的结果为函数的参数)作为初值,而调用端所获得的也是函数返回值的一个副本(就是以返回值为本,调用copy-constructor返回一个临时对象,)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值