c知识点

知识点总结

数据存放位置

  1. 本地变量:栈
  2. new出的对象:堆
  3. static/全局变量:全局数据区

c++内存模型

  • 存放对象的地方
    1. 全局数据区
  • 访问对象的方式
    1. 变量访问对象
    2. 指针访问对象
    3. 引用访问对象

class

  • struct默认public
  • class默认private
  • 其他用法完全一样,都包含成员函数、继承、多态

const

  • 只需看其右侧最近的类型
    • *前后
      • 前:指针指向变量
      • 后:指针本身是变量
    • 函数前后
      • 前:函数返回值为const
      • 后:函数成员为const
      • 最后:此成员函数不改变类中的成员变量(mutable可变的)

static

  • 静态局部变量:
    • 全局数据区分配内存
    • 随函数第一次调用时初始化,程序结束时销毁
    • 声明处初始化,若无显式初始化,会自动初始化为0
    • 作用域为局部作用域
  • 静态全局变量:
  • 静态函数:
    • 本文件可见(文件隔离)
  • 静态数据成员:
    • 只有class有一份,而普通数据成员是每一个实例有一份
  • 静态成员函数:
    • 静态成员函数不能访问非静态(成员函数、数据成员)
    • 非静态成员函数可以访问静态(成员函数、数据成员)
    • 解释:静态是属于类的,它不知道创建了多少对象;而对象中的数据对类中数据一清二楚

&

  • 引用
    • 在赋值=右侧
    • 和变量在一起
  • 取地址
    • 在赋值=左侧
    • 和类型在一起

初始化

  • A::A(int m, int n) : x(m), y(n) {} //初始化
  • A::A(int m, int n){x = m; y = n;} //赋值
  • singleton模式:local static对象替换non-local static对象
    • 基础在于:c++保证,函数内的local static对象会在”该函数被调用期间“”首次遇上该对象之定义式“时被初始化。

volatile

  • 声明的变量可能随时变化,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问
  • 从所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。
  • 应用在共享变量

template

// TODO:

virtual

  • virtual析构函数用于多态基类的声明
  • 被用作base class的类声明为virtual析构函数,其他类不要声明virtual析构函数(对象体积增大,不能将其传给其他语言写的函数-无移植性)
  • 类的设计目的如果不是base class或具有多态性,就不该声明virtual析构函数
  • 别让异常逃出析构函数
    • 结束程序 try{…}catch{…;std::abort;}
    • 吞掉异常  try{…}catch{…;}
    • 前两者的优化: 

构造/析构函数

  • 构造函数调用顺序:base -> derived
  • 析构函数调用顺序:derived -> base
  • 在构造/析构函数中不要调用虚函数,因为这类的调用不会下降至derived class(相对的)

operator

  • 令重载操作符返回一个reference to *this
  • 处理自我赋值(赋值时两个为同一个对象,删除一个就都删除了)
    • 证同测试,并跳过处理流程
    • 用副本去操作
    • copy and swap
  • copy函数
    • 确保复制”对象内的所有成员变量” 和 “所有base class成分”
    • 不要用一个copy函数实现另一个copy函数,应该将共同机能放入第三函数,并由两个函数共同调用

指针、引用

  • 指针
    • 概述:指针传递参数本质上是值传递的方式,其传递一个地址值
    • 流程:值传递的过程中,被调函数的形参作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为实参的一个副本
    • 特点:被调函数对形参的任何操作都是作为局部参数进行,不影响主调函数是参变量的值
    • 应用:
      • 不改变指针指向,形参指向实参,可操作实参
      • 改变指针指向,则形参作为副本,与实参无关,不可操作实参
  • 引用
    • 概述:引用传递本质是地址传递,传递的是实参变量的地址
    • 流程:被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
  • 区别
    • 指针传递参数时,指针中存放的也是实参的地址,但是在被调函数内部指针存放的内容可以被改变,即可能改变指向的实参,所以并不安全
    • 而引用则不同,它引用的对象的地址一旦赋予,则不能改变

双指针、指针引用

// TODO:

条件编译

  • 当标识符定义过了,编译程序段1,否则编译程序段2
    1
    2
    3
    4
    5
    #ifdef 标识符
    程序段1
    else
    程序段2
    #endif

资源管理

  • 以对象管理资源
    • 为防止资源泄露,请使用RAII对象(tr1::shared_ptr、auto_ptr),它们在构造函数中获得资源并在析构函数中释放资源

提供对原始资源的访问

  • 问题:如何调用一个对象

    1
    2
    3
    std::tr1::shared_ptr<Investment>pInv(createInvestment());
    int daysHeld(const Investment* pi); // 返回投资天数
    int days = daysHeld(pInv); // 调用出错

    编译不通过,daysHeld需要Investment*指针,传入的却是类型为tr1::shared_ptr的对象

  • 解决办法:

    • 智能指针
      • 显示转换: trl::shared_ptr和auto_ptr都提供了一个get成员函数,它会返回只能指针内部原始资源指针(的复件)
      • 隐式转换: 利用重载了的取值操作符(operator->和operator*),其允许隐式转换至内部原始指针
      • 1
        2
        3
        4
        5
        6
        7
        8
        9
        FontHandle getFont();   //API
        void releaseFont(FontHandle fh); // API
        class Font {
        public:
        explicit Font(FontHandle fh) : f(fh){} // 获取资源,pass-by-value
        ~Font() {releaseFont(f);} // 释放资源
        private:
        FontHande f; // 原始字体资源
        };

        font类中添加两种解决办法

      • 显式转换

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        class Font {
        public:
        ...
        FontHandle get() const {retun f;} //显示转换
        ...
        };

        //调用
        void changeFontSize(FontHandle f, int newSize); // API
        Font f(getFont());
        int newFontSize;
        cangeFontSize(f.get(), newFontSize); //显示将Font转换为FontHandle

        问题: 增加泄漏字体的可能性,而Font类的主要设计目的是为了防止资源(字体)泄露

      • 隐式转换

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        Class Font {
        public:
        ...
        operator FontHandle() const {return f;} // 隐式转换
        ...
        };

        // 调用
        Font f(getFont());
        int newFontSize;
        changeFontSize(f, newFontSize); // 将Font隐式转换为FontHandle

        问题:

        1
        2
        3
        Font f1(getFont());
        FontHandle f2 = f1; // 原意是要拷贝一个Font对象
        //却反将f1隐式转换为FontHandle对象,然后才复制它
-------------本文结束感谢您的阅读-------------
显示 Gitment 评论