Effective C++读书笔记——(一)Prefer consts, enums, and inlines to #defines

const与#define的不同之处和const的优势早已耳熟能详,而Effective C++(后面简称EC)对这个话题的阐述使我有了几点新的认识:

1. it's important that the pointer be declaredconst, usually in addition to what the pointer points to. To define a constantchar*-based string in a header file, for example, you have to writeconsttwice:

一个指针,除了注意他指向的类型是否为常量外,还要注意指针本身是否需要为常量。要定义一个char *类型的字符串常量,需要写两个const才行:

const char * const authorName = "Scott Meyers";

等同于:

const  string authorName("Scott Meyers");

2. The enum hack is worth knowing about for several reasons. First, the enum hack behaves in some ways more like a#define than aconst does, and sometimes that's what you want. For example, it's legal to take the address of aconst, but it's not legal to take the address of an enum, and it's typically not legal to take the address of a#define, either.

...

Also, though good compilers won't set aside storage for const objects of integral types (unless you create a pointer or reference to the object), sloppy compilers may, and you may not be willing to set aside memory for such objects. Like#defines, enums never result in that kind of unnecessary memory allocation.

为什么enum类型是不能取址的?为什么#define和enum是不会分配空间的?

希望知道的人不吝赐教。谢谢。

3. 不管是面试还是笔试,经常会被问到下面的表达方式是否合理:

#define CALL_WITH_MAX(a, b) f(a > b ? a : b)

答案当然是不合理,原因是用宏来表达函数时,参数一定要加括号保护,以避免出现意想不到的运算结果。很多书上都讲要给函数的参数加括号。那是不是加了括号就一定没有问题了呢。以前我是这么认为的,没有考虑更多。EC告诉我,这样还是不够安全,比如把上面的表达式换成:

#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))

如果

int a = 5, b = 0;

那么

CALL_WITH_MAX(++a, b);          // a is incremented twice

CALL_WITH_MAX(++a, b+10);       // a is incremented once

由于入参的不同,导致a被运算了不同的次数。

所以最好是使用内联函数(inline)来替换用宏表达的函数:

template<typename T>                               // because we don't know what T is, we pass by reference-to-const 

inline void callWithMax(const T& a, const T& b)   

{                                                  

    f(a > b ? a : b);                               

}

这样就算不加括号也不用担心上面的问题,而且callWithMax是一个真实的函数,可以有自己的使用范围和访问权限,比如把他声明为一个类的private成员函数。而使用宏通常是不能做到这些的。

4. 今天还照着EC写了一段代码,收获很多。

class TextBlock {
private:
    string text;
public:
    TextBlock(string txt) {
        text = txt;
    }
     char& operator[] (size_t position)   {
        cout  <<  "const"  <<  endl;
        return text[position];
    }
    const char& operator[] (size_t position) const {
        cout  << "not const" << endl;
        return text[position];
    }
    void print() const {
        cout << text << endl;
    }
};
int main() {
	TextBlock tb("Hello");
    cout << tb[0] << endl;
    tb.print();

    const TextBlock ctb("World");
    cout << ctb[0] << endl;
    ctb.print();
    getch();
    return 0;
}


这里如果把void print() const或者const char& operator[] (size_t position) const中的const修饰符去掉,ctb的调用就会报错。而如果把第一个运算符重载函数char& operator[] (size_t position)去掉,tb的调用不会有问题。原因是:

在调用上,在未指明为const的类调用时,使用的是非const的函数。如果没有非const的函数,他才会调用const的函数。而如果const的类去调用非const的函数,会直接报错。所以在写代码时,可以考虑是不是可能会修改成员,如果希望是不修改的,那么请用const。

 5. 同样以上面的代码为基础,

class TextBlock {
private:
    string text;
public:
    TextBlock(string txt) {
        text = txt;
    }
      char& operator[] (size_t position)   {
        cout  <<  "const"  <<  endl;
        return text[position];
    }
     /*
    const char& operator[] (size_t position) const {
        cout  << "not const" << endl;
        return text[position];
    }
    */
    void print() const {
        cout << text << endl;
    }
};
int main() {
	TextBlock tb("Hello");
    cout << tb[0] << endl;
    tb.print();
/*
    const TextBlock ctb("World");
    cout << ctb[0] << endl;
    ctb.print();
    */
    getch();
    return 0;
}

这段代码运行没有问题。如果把char& operator[] (size_t position)改为char& operator[] (size_t position) const,就会编译报错:

error C2440: 'return' : cannot convert from 'const char' to 'char &'

这是因为,用const修饰的成员函数本身是限制不更改成员变量的,函数中确实也没有修改,但是返回的是一个引用,编译器发现有成员变量可能在该函数外部被修改,所以报错。所以这里要么改为
const char& operator[] (size_t position) const

要么改为

char operator[] (size_t position) const

后一种改法返回的是char的一个拷贝,就算被修改了也不会影响成员变量。

考虑到函数本身是没有修改成员变量的需求的,所以源代码中完全不加const的做法欠妥当。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值