zoukankan      html  css  js  c++  java
  • EffectiveC++01-03

    导读

    作者Scott Meyers在如何有效运用C++方面给出了55个具体的做法,大致分为两类:

    • 一般性的设计策略,集中于"如何在不同的做法中选择一种完成任务"
      • 选择inheritance(继承)还是template(模板)
      • 选择public继承还是private继承
      • 选择private继承还是composition(复合)
      • 选择member函数还是non-member函数
      • 选择pass-by-value还是pass-by-reference
    • 具体细节的特定语言特性
      • 什么是assignment操作符的适当返回类型
      • 何时该令析构函数为virtual
      • operator new无法找到足够内存时,该如何行事

    术语

    声明式(declaration)是告诉编译器某个东西的名称和类型

    extern int x;                       // 对象声明式
    std::size_t numDigit(int number);   // 函数声明式
    class Widget;                       // 类声明式
    template<typename T>                
    class GraphNode;                    // 模板声明式
    

    定义式(definition)是编译器为此对象拨发内存的地点

    int x;                              // 对象定义式
    std::size_t numDigit(int number){   // 函数定义式
        return number;
    }
    
    class Widget{                       // 类定义式
        public:
            Widget();
            ~Widget();
    };
    
    template<typename T>                // 模板定义式
    class GraphNode{
        public:
            GraphNode();
            ~GraphNode();
    };
    
    

    copy构造和copy赋值的区别:一个新对象被定义,一定是构造函数被调用,不可能调用赋值操作

    条款01:视C++为语言联邦

    C++有四个次语言

    • C:没有模板(templates),没有异常(exceptions),没有重载(overloading)..
    • Object-Oriented C++:C with Classes, 封装,继承,多态,虚函数绑定...
    • Template C++:模板元编程(TMP)...
    • STL:容器,迭代器,算法,函数对象...

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

    这个条款或许更改为"宁可以编译器替代预处理器"比较好

    #define ASPECT_RATIO 1.653
    

    ASPECT_RATIO可能从未进入符号表,从未被编译器看见,可以用一个常量来替代宏

    const double Aspect_Ratio = 1.653; // 大写名称常用于宏,这里改变名称写法
    
    

    当以常量替换#define时,有两种特殊情况

    • 定义常量指针
      由于常量定义式通常放在头文件中,因此有必要将指针也声明为const
    const char* const authorName = "Scott Meyers";
    
    • class专属常量
      为了将常量作用域限制为class内,必须让它成为一个成员,为确保常量最多一份,必须让它成为一个static
      通常C++要求你对所有你使用的任何东西提供一个定义式,但是如果是class专属常量且是static且为整数类型(int,char,bool),则特殊处理,只要不取地址,你可以声明他们而无须提供定义式,如下。但如果需要取其地址,就必须提供在实现文件中提供定义式,否则编译不通过。
    // GamePlayer.h
    class GamePlayer{
    public:
        static const int print(){ return NumTurns;}
        static const int* address(){ return &NumTurns;}
    private:
        static const int NumTurns = 5; // 常量声明式
    };
    
    
    // GamePlayer.cpp
    #include <iostream>
    #include "GamePlayer.h"
    
    const int GamePlayer::NumTurns; // 定义式,初始值声明式已获得,不能再设初值
    int main(){
        // GamePlayer::print();
        std::cout << GamePlayer::address();
        return 0;
    }
    

    顺带一提,#define宏无法提供封装性,如果编译器不允许"static整数型class常量"完成"in class初值设定",可以改用"the enum hack"补偿做法,其理论基础是枚举类型的数值可以当成int使用

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

    enum hack行为比较像#define而不像const,有时候这正是你想要的,如取地址的合法性(const合法,#define和enum不合法),enum hack还是模板元编程的基础技术(条款48)
    宏不会招致函数调用的额外开销,但是容易误用

    #define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b)) // 以较大值调用f
    
    int a = 5, b = 0;
    CALL_WITH_MAX(++a, b);                              // a被累加两次
    CALL_WITH_MAX(++a, b+10);                           // a被累加一次
    

    而tempalte inline(条款30)可以获得宏带来的效率和所有可预料的行为以及类型安全性

    条款03:尽可能使用const

    const如果出现在*左边,表明被指物是常量,在右边则表明指针自身为常量

    void f(const Widget* pw);        //pw所指之物为常量
    void f(Widget const* pw);        // 同上
    

    STL中const_iterator指的是所指物不能改动

    const成员函数

    • 可以使用const成员函数使接口更容易被理解
    • 可以使操作const对象成为可能,以pass-by-reference-to-const传递对象能够改善程序效率
    • 两个成员函数如果只是常量性不同,可以重载

    成员函数如果是const意味着什么?

    • bitwise constness(physical constness)
      不改变对象内的任何一个bit,很容易侦测违反点:编译器只需寻找成员变量的赋值动作即可,这也是C++对常量性的定义,因此const成员函数不可以更改对象内的任何non-static成员变量
    • logical constness
      const成员函数可以修改对象内的某些bits,但是只有在客户端(调用端)侦测不出的情况下才如此

    声明为mutable的变量即使在const成员函数中也可以被更改

    在const和non-const成员函数中避免代码重复

    运用const成员函数实现non-const成员函数,可以使用const_cast进行常量性转除

    
    class TextBook{
    public:
        const char& operator[](size_t position) const{
            return text[position];
        }
    
        char& char& operator[](size_t position){
            return const_cast<char&>(
                static_cast<const TextBook&>(*this)
                [position]
                );
        }
    };
    
  • 相关阅读:
    split 使用
    python中接受上一条命令执行的结果----subprocess.check_output()
    k8s开启cadvisor http 服务
    Spring Cloud之配置中心搭建
    如何高效地学习开源项目
    Spring Boot之默认连接池配置策略
    Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: ..... this is incompatible with sql_mode=only_full_group_by
    com.netflix.zuul.exception.ZuulException: Forwarding error
    设置环境变量相关命令
    java.lang.NoClassDefFoundError: org/springframework/web/context/WebApplicationContext
  • 原文地址:https://www.cnblogs.com/qbits/p/11042879.html
Copyright © 2011-2022 走看看