设为首页 加入收藏

TOP

Chapter 1(一)
2023-07-23 13:28:32 】 浏览:70
Tags:Chapter

1 让自己习惯C++

条款 01 视 C++ 为一个语言联邦

  • C : C++以C为基础,block、语句、预处理器、内置数据类型、数组、指针都来自于C。当使用C++中的C成分工作时,没有模板(Template)、没有异常(Exceptions)、没有重载(overloading)。

  • Object-Oriented C++ : 也就是 C with classes,classes(包括构造函数和析构函数)、封装(encapsulation)、继承(inheritance)、多态(polymorphism)、virtual函数(动态绑定)......等等。

  • Template C++ : C++的泛型编程部分。

  • STL(Standard Template Library) : 对容器、迭代器、算法以及函数对象对的规约有极佳的紧密配合与协调。

*请记住 : *

? 1. 高效编程守则视状况而变化,取决于你使用C++的哪一部分。

条款 02 尽量以 const,enum,inline 替代 #define

例 : `#define ASPECT_RATIO 1.653`预处理器会将程序中的`ASPET_RATIO`记号全部替换成数值`1.653`,也就是这个记号不会进入记号表内,这样在程序出错时获取的错误信息会很难分析。

? 当我们使用#define 实现宏时,更要小心,必须为宏中的所有实参加上小括号。例 :

#define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b))//一定要加小括号,这里的例子还体现不出什么,注意加括号的位置就行

int a = 5,b = 0;
//当第一个参数(++a)大于第二个参数时,++a会被执行两次,这显然很容易出问题
CALL_WITH_MAX(++a,b);
CALL_WITH_MAX(++a,b+10);

?

解决方法 :

  1. 以一个常量替换上述宏。

    const double Aspect_ratio = 1.653; 作为一个语言常量,自然会进入记号表,这样在Debug的时候容易跟踪,且生成的代码量比较小,开支较小,因为宏定义是盲目地替换字段。

    以 const 代替 #define 时要注意两点 :

    ? (1) 定义常量指针时,要注意顶层 const 和底层 const 的区别。顶层 const 是将 const 放在 '*' 左边,意思是指针指向的常量类型,所以该指针所指向的内容不能被修改;

    ? 而底层 const 则是将 const 放在 '*' 右边,意思是我这个指针是一个常量指针,只能指向在初始化时的值,不能指向其他变量。

    ? (2)定义 class 专属常量时,也就是类内 static 成员,例如

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

    ? 注意,上例中的的static const int NumTurns = 5; 是声明式而不是定义式。C++要求要对使用的任何东西都要提供一个定义式。

    ? 但如果它是个 class 专属常量,又是 static 且为整数类型(integral type,例如int,char,bool),只要不取指针,则只需要提供声明式,若有些编译器不支持,则需要在实现文件中定义。(注意非整型必须定义,初值可以放在定义式中)

    //.h
    class CostEstimate{
    private:
        static const double FudgeFactor;
    };
    
    //.c
    const double CostEstimate::FudgeFactor = 1.35;
    

    ? 另外,#define 不重视作用域(scope),在定义后编译过程中都有效。

  2. 使用 enum hack

    这种做法比较像#define,同样不能取地址,同样会导致非必要的内存分配。

  3. 对于“实现宏“,用template inline函数,同样是代码替换,但这种做法属于函数操作,一切按函数操作就行了,不用操心参数问题,同时遵守作用域和访问规则。

请记住:

? 1. 对于单纯常量,最好以 const 对象或 enum 替换 #define

2. 对于形似函数的宏(macros),最好改用 inline template 函数替代 #define

条款 03 尽可能使用const

? 顶层 const : 表示 const 修饰的类型为常量,特别地,对于指针类型,const 在 ‘*’ 右边时表示顶层指针,也就是该指针变量为常量, 与该指针变量指向的对象是否为常量无要求。

int i = 0;
int *const p1 = &i;//const 在‘*’右边,表示p1只能指向i(顶层指针)

? 底层 const : 与指针和引用类型有关,对于指针类型,当 const 在 ‘*’ 左边(一般写在类型左边)时,表示该指针指向的对象为常量类型, 此时该指针可以指向别的对象,当不能通过指针解引用来更改所指对象的值。

? 而对于引用类型,都是底层 const,也就是所引用的值为常量,但const引用可以绑定常量与非常量,这是一个特殊的例子。

int i = 0;
const int j = 1;
const int &ref_i = i;//可以绑定非常量
const int &ref_j = j;//可以绑定常量类型
const int &ref = 10;//会创建临时变量,然后绑定

? const可以和函数的返回值、参数、函数自身产生关联,尽可能地使用它,可以让编译器帮你更快的发现错误!

const成员函数

? 将 const 作用在成员函数上,可以区分出常量对象和非常量对象所使用的不同版本的成员函数。const成员函数可以保证不修改类的成员变量。

//.h
class TextBlock{
public:
   // ...
    const char& operator[](std::size_t position) const//const对象调用此函数
    { return text[position]; }
    char& operator[](std::size_t position)//非const对象调用此函数
    { return text[position]; }
private:
    std::string text;
};

//.cpp
TextBlock tb("Hello");
std::cout << tb[0];//调用 char& operator[](std::size_t position)

const TextBlock ctb("Hello");
std::cout << ctb[0];//调用 const char& operator[](std::size_t position) const

? 在C++中,不修改类的成员变量指的是编译器强制实施的“bitwise constness”,也就是保证每一个bit都不允许修改,但现实中,我们可能会希望一部分成员不被修改,一部分成员被修改。

? 此时,我们可以将能在const成员函数中修改的成员变量声明为mutable

//.h
class CTextBlock{
public:
    //...
    std::size_t length() const;
private:
    char* pText;
    mutable std::size_t textLength
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++面试八股文:了解位运算吗? 下一篇const char* , char const* 和cha..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目