Effective C++ 学习日记

Effective C++ 学习日记

Effective C++ 学习日记&&1

听说Effective C++这本书很不错,来学习一下,并做个记录。

C++ 多重泛型编程

1.过程
2.面向对象
3.函数
4.泛型
5.元编程
C++可看为由四个次语言组成的集合:C,OO,Template, STL.

Prefer consts,enums and inlines to #define

宁可以编译器替换预处理器

#define ASPECT_RATIO  1.635

ASPECT_RATIO 记号名称可能从未被编译器看见,或在编译器处理源码之前被预处理器移走了,可能并未进入记号表。
解决方法:

const  double  aspectRatio  =  1.635;

常量
常量指针
常量定义通常置于头文件便于被不同源码包含,有必要将指针声明为const.
例如定义常量字符串:

const char* const authorName = "Zac Lipschiyz";

使用string更好:

const std::string authorName = "Zac Lipschiyz";

class 专属常量
为了将常量作用于限制于class内,使用成员变量;
为了只有一份实体,使用static;

class GamePalyers
{
private:
	static const int NumTurns = 5;
	int scores[NumTurns];
};

上述为声明式而非定义式,如果实现文件中需定义式:

const int GamePalyers::NumTurns;

赋初值可在声明时,也可在定义时,但不可重复赋值。
成员变量是可以被封装的,而#define不行。
注意如果编译器不允许“static 整数型 class 常量”完成“int class 初值设定”,可用enum来替代,一个枚举类型的数值可权充ints被使用。

class GamePalyers
{
private:
	enum { NumTurns = 5 };
	int scores[NumTurns];
};

the enum hack值得了解
一、不想让别人获取整数常量的指针或引用,可用enum;
二、模板元编程的基础技术。
预处理器
#define误用宏,宏看起来像函数,但不会招致函数调用带来的额外开销:

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

定义时所有的实参要加上小括号,单尽可能不用

int a = 5, b = 0;
CALL_WIHT_MAX( ++a, b );
CALL_WIHT_MAX( ++a, b + 10 );

这种调用不堪入目,还好可用template inline函数。
template inline函数
可获得宏带来的效率及一般函数的所有可预料行为和类型安全性。

template<typename T>
inline void callWithMax(const T& a, const T& b)
{
	f(a > b ? a : b);
}

callWithMax是个真正的函数,遵守作用域和访问规则,可用于类中。
请记住
对于单纯常量,最好用const对象或enums替换#defines;
对于形似函数的宏,最好改用inline函数来替换#defines.

尽可能使用const

const指定一个语义约束,不该被改动的对象。

char greeting[] = "Hello";
char* p = greeting;			         // non-const pointer, non-const data
const char* p = greeting;			 // non-const pointer, const data
char* const p = greeting;			 // const pointer, non-const data
const char* const p = greeting;	     // const pointer, const data

const data两种写法

void f1(const Widget* pw);
vodi f2(Widget const * pw);

STL迭代器指针

T* const     // const pointer, non-const data
const T*     // non-const pointer, const data

iterator与const_iterator区别
const + iterator:

std::vector<int> vec = { 1, 2, 3 };
const std::vector<int>::iterator iter = vec.begin();      //T* const
*iter = 10;           //const pointer, non-const data
++iter;              //error

const_iterator:

std::vector<int> vec = { 1, 2, 3 };
std::vector<int>::cosnt_iterator iter = vec.begin();      //const T*
*iter = 10;           //error
++iter;              //non-const pointer, const data

const于函数声明的应用

class Rational { ... };隐式转换为
const Rational operator* (const Rational& lhs, const Rational& rhs);

const避免像两个数值乘积后再赋值,有可能隐式转换为bool类型,造成与内置类型不兼容的情况,故将回传值声明为const,避免赋值修改情况。

const成员函数
将const实施于成员函数,是为了确认该成员函数可作用于const对象身上。

class TextBlock
{
public:
    TextBlock(const std::string text)
        :text_(text)
    {}

    virtual ~TextBlock() = default;

    const char& operator[](std::size_t position) const { return text_[position]; }
    char& operator[](std::size_t position) { return text_[position]; }
private:
    std::string text_;
};

对比输出:

TextBlock tb("hello");
std::cout << tb[0] << std::endl;      //h
const TextBlock tb1("world");
std::cout << tb1[0] << std::endl;     //w

这不足以体现区别,不妨添加print函数:

void print(const TextBlock& ctb) 
	{ std::cout << ctb[0] << std::endl; }

此时print函数只会调用,因为入参由const限定:

    const char& operator[](std::size_t position) const { return text_[position]; }

而如果进行修改:

TextBlock tb("hello");
std::cout << tb[0] << std::endl;
print(tb);
tb[0] = 'x';          
const TextBlock tb1("world");
std::cout << tb1[0] << std::endl;
print(tb1);
tb1[0] = 'y';      //ERROR

错误原因是试图对const返回值进行赋值操作。

bitwise constness
const成员函数不可以更改对象内任何non-static成员变量。
如果这样的成员函数:

char& operator[](std::size_t position) const { return pText_[position]; }
private:
    char* pText_;

那么如下调用会发生:

char test[] = "world";
const TextBlock tb2(test);
std::cout << tb2[0] << std::endl;     //w
char* pc = &tb2[0];
pc[0] = 'x';
std::cout << tb2[0] << std::endl;     //x

logical constness
一个const成员可以修改它所处理的对象内的某些bits.

private:
    char* pText_;
    std::size_t text_length_;
    bool length_is_valid_;
std::size_t TextBlock::length() const
{
    if (!length_is_valid_)
    {
        text_length_ = std::strlen(pText_);    //ERROR
        length_is_valid_ = true;               //ERROR
    }
    return text_length_;
}

text_length_和length_is_valid_都可能被修改的,但是编译器会报错,因为编译器都认定bitwise constness.
解决办法:
利用C++的一个与const相关的摆动场:mutable(可变的)。
mutable释放掉non-static成员变量的bitwise constness约束。

private:
    char* pText_;
    mutable std::size_t text_length_;
    mutable bool length_is_valid_;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值