• 读《高质量C++编程》总结


    今天翻了一遍《高质量C++编程》,为了以后再次回顾,做了如下记录与一些自己的总结。

    1.头文件包含问题

    为了防止头文件被重复引用,应当用 ifndef/define/endif 结构产生预处理块。

       也可以使用另一种方式:#pragma once  相信很多人知道,作用和上面是一样的。


    2.循环语句效率

    在多重循环中,如果可以,应当将最长的循环放在最内层,最短的循环放在最外层,以减少 CPU 跨切循环层的次数

    如:

    for(i = 0; i<500; i++)

    {

        for(j=0; j<10; j++)

        {

              //xxx

        }
    }//不良写法


    应改为:

    for(i = 0; i<10; i++)

    {

        for(j=0; j<500; j++)

        {

              //xxx

        }
    }

    另外,如果循环体内存在逻辑判断,并且循环次数很大,可以将逻辑判断移到循环体的外面。


    3.switch语句

    Java中

    1. byte、char、short、int四种基本类型以及它们的包装类(需要Java5.0/1.5以上版本支持)都可以用于switch语句。

    2. long、float、double、boolean四种基本类型以及它们的包装类(在Java所有版本中)都不能用于switch语句。

    3. enum类型,即枚举类型可以用于switch语句,但是要在Java5.0(1.5)版本以上才支持。

    4. 所有类型的对象(包括String类,但在Java5.0/1.5以上版本中,该项要排除byte、char、short、int四种基本类型对应的包装类)都不能用于switch语句。

     

    C++中

    1. char、short、int、long、bool四种基本类型都可以用于switch语句。

    2. float、double都不能用于switch语句。

    3. enum类型,即枚举类型可以用于switch语句。

    4. 所有类型的对象都不能用于switch语句。(比如string,可以自己试试)


    4.常量

    1.不能在类声明中初始化 const 数据成员

    class A
    {…
        const int SIZE = 100;    //  错误,企图在类声明中初始化 const 数据成员
        int array[SIZE];     //  错误,未知的 SIZE
    };

    2.const 数据成员的初始化只能在类构造函数的初始化表中进行

    class A
    {…
        A(int size);    //  构造函数
        const int SIZE ;
    };
    A::A(int size) : SIZE(size)  //  构造函数的初始化表
    {
        …
    }

    3.C++中的常量用const声明,C语言中用的是#define。

       const最大的用处是用在函数的参数修饰,比如函数的一个参数是指针,如果这个函数在以后的工作中不会改变指针指向的变量的话,要在指针前加const,避免以后意外的改变。


    5.static成员变量与函数

       static类型的类成员变量必须在类外初始化;

       static成员函数不依赖于类,相当于类里的全局函数(可以由该类对象调用,也可以 类名::函数名()的形式调用)

       static成员函数相当于把访问范围限制在所在的类中!  注意:不能访问类中非static成员变量以及成员函数。

       static成员函数在实际中可以用作线程函数。


    6.指针与引用

        如果函数的返回值是一个对象,有些场合用“引用传递”替换“值传递”可以提高效率。而有些场合只能用“值传递”而不能用“引用传递” ,否则会出错。

    例如:

        class String
        {…
            //  赋值函数
            String & operate=(const String &other);  
            //  相加函数,如果没有 friend 修饰则只许有一个右侧参数
            friend  String operate+( const String &s1, const String &s2);
        private:
            char *m_data;
        }:



    String 的赋值函数 operate =  的实现如下:

        String& String::operate=(const String &other)
        {
            if (this == &other)
                   return *this;
            delete m_data;
            m_data = new char[strlen(other.data)+1];
            strcpy(m_data, other.data);
            return *this;   //  返回的是 *this 的引用,无需拷贝过程
        }


    对于赋值函数,应当用“引用传递”的方式返回 String 对象。如果用“值传递”的
    方式,虽然功能仍然正确,但由于 return 语句要把*this 拷贝到保存返回值的外部存
    储单元之中,增加了不必要的开销,降低了赋值函数的效率。


    String 的相加函数 operate +  的实现如下:

        String operate+(const String &s1, const String &s2)  
        {
            String  temp;
            delete temp.data;  // temp.data 是仅含‘ 0’ 的字符串
            temp.data = new char[strlen(s1.data) + strlen(s2.data) +1];
            strcpy(temp.data, s1.data);
            strcat(temp.data, s2.data);
            return temp;
        }

    对于相加函数,应当用“值传递”的方式返回 String 对象。如果改用“引用传递”,
    那么函数返回值是一个指向局部对象 temp 的“引用”。 由于 temp 在函数结束时被自动销毁,将导致返回的“引用”无效


    7.extern c的问题

    如果 C++ 程序要调用已经被编译后的 C 函数,该怎么办?
    假设某个 C 函数的声明如下:
    void foo(int x, int y);
    该函数被 C 编译器编译后在库中的名字为_foo,而 C++编译器则会产生像_foo_ int_ int之类的名字用来支持函数重载和类型安全连接。由于编译后的名字不同,C++ 程序不能直接调用 C 函数。C++ 提供了一个 C 连接交换指定符号 extern “C”来解决这个问题。
    例如:
    extern “C”
    {
        void foo(int x, int y);
        … // 其它函数
    }
    或者写成
    extern “C”
    {
         #include “myheader.h”
         … // 其它 C 头文件
    }
    这就告诉 C++ 编译译器,函数 foo 是个 C 连接,应该到库中找名字_foo 而不是找
    _foo_int _ int 。C++ 编译器开发商已经对 C 标准库的头文件作了 extern “C”处理,所以我们可以用#include  直接引用这些头文件。


    8.参数缺省值

    参数缺省值只能出现在函数的声明中,而不能出现在定义体中。
    例如:
    void Foo(int x=0, int y=0);  //  正确,缺省值出现在函数的声明中
    void Foo(int x=0, int y=0)     //  错误,缺省值出现在函数的定义体中
    {

    }


    9.运算符重载

    如果运算符被重载为全局函数,那么只有一个参数的运算符叫做一元运算符,有两个参数的运算符叫做二元运算符。
    如果运算符被重载为类的成员函数,那么一元运算符没有参数,二元运算符只有一个右侧参数,因为对象自己成了左侧参数



    10.重载、覆盖与隐藏

    成员函数被重载的特征:
    (1 )相同的范围(在同一个类中);
    (2 )函数名字相同;
    (3 )参数不同;
    (4 )virtual 关键字可有可无。


    覆盖是指派生类函数覆盖基类函数,特征是:
    (1 )不同的范围(分别位于派生类与基类);
    (2 )函数名字相同;
    (3 )参数相同;
    (4 )基类函数必须有 virtual 关键字。

    隐藏:

    (1 )如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual
    关键字,基类的函数将被隐藏(注意别与重载混淆)。
    (2 ) 如果派生类的函数与基类的函数同名, 并且参数也相同, 但是基类函数没有 virtual
    关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
    ————————————————
    版权声明:本文为CSDN博主「风雨也无晴」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/scottly1/article/details/24535783

  • 相关阅读:
    四、单片机学习——矩阵键盘实验
    二、单片机学习——独立按键实验
    三、单片机学习——数码管实验(共阳)
    一、单片机学习——流水灯实验
    Cacti监控Linux安装配置snmp服务
    firewalld和iptables区别
    Zabbix图形界面乱码修复为中文显示
    Centos7安装Zabbix 5.0 LTS 版本安装(详细版)
    Ubuntu Server 18.04 网络配置
    linux下开启root用户远程登录,允许无密码登录
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/14643390.html
Copyright © 2020-2023  润新知