c++那些事 笔记

C++那些事

const 类型作用

  1. 修饰变量:常量(相比#define,可以节省空间,避免#define定义的常量在内存中有若干个拷贝;防止被修改;类型检查)
  2. 修饰指针:不同位置作用不同,在变量前代表指针不可改变,其他位置代表指针指向的内容不可变
  3. 修饰参数:不可修改参数
  4. 修饰函数:函数体不可修改类对象
  5. 修饰函数返回值:返回值不可变
  6. const对象默认为文件局部变量

类成员const变量只能在初始化列表进行初始化
this 指针默认是 T * const,对const函数会变成 const T const*
引用在设置后就不能修改了

内联函数

内联能提高函数效率,但并不是所有的函数都定义成内联函数!内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。

  1. 如果执行函数体内代码的时间相比于函数调用的开销较大,那么效率的收货会更少!
  2. 另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。

虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联。内联是在编译器建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。

虚函数

构造函数可以为虚函数吗?
构造函数不可以声明为虚函数。同时除了inline之外,构造函数不允许使用其它任何关键字。
为什么构造函数不可以为虚函数?
尽管虚函数表vtable是在编译阶段就已经建立的,但指向虚函数表的指针vptr是在运行阶段实例化对象时才产生的。 如果类含有虚函数,编译器会在构造函数中添加代码来创建vptr。 问题来了,如果构造函数是虚的,那么它需要vptr来访问vtable,可这个时候vptr还没产生。 因此,构造函数不可以为虚函数。我们之所以使用虚函数,是因为需要在信息不全的情况下进行多态运行。而构造函数是用来初始化实例的,实例的类型必须是明确的。 因此,构造函数没有必要被声明为虚函数。

volatile

  • volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素(操作系统、硬件、其它线程等)更改。所以使用 volatile 告诉编译器不应对这样的对象进行优化。
  • volatile 关键字声明的变量,每次访问时都必须从内存中取出值(没有被 volatile 修饰的变量,可能由于编译器的优化,从 CPU 寄存器中取值)
  • const 可以是 volatile (如只读的状态寄存器)
  • 指针可以是 volatile

位域

http://www.yuan-ji.me/C-C-%E4%BD%8D%E5%9F%9F-Bit-fields-%E5%AD%A6%E4%B9%A0%E5%BF%83%E5%BE%97/

explicit

  1. explicit 修饰构造函数时,可以防止隐式转换和复制初始化
  2. explicit 修饰转换函数时,可以防止隐式转换,但按语境转换除外

不允许类似B b2 = 1;的隐式转换。

using

  • 在继承过程中,派生类可以覆盖重载函数的0个或多个实例,一旦定义了一个重载版本,那么其他的重载版本都会变为不可见。
    如果对于基类的重载函数,我们需要在派生类中修改一个,又要让其他的保持可见,必须要重载所有版本,这样十分的繁琐。
#include <iostream>
using namespace std;

class Base{
    public:
        void f(){ cout<<"f()"<<endl;
        }
        void f(int n){
            cout<<"Base::f(int)"<<endl;
        }
};

class Derived : private Base {
    public:
        using Base::f;
        void f(int n){
            cout<<"Derived::f(int)"<<endl;
        }
};

int main()
{
    Base b;
    Derived d;
    d.f();
    d.f(1);
    return 0;
}
  • 取代typedef
    C中常用typedef A B这样的语法,将B定义为A类型,也就是给A类型一个别名B
    对应typedef A B,使用using B=A可以进行同样的操作。
typedef vector<int> V1; 
using V2 = vector<int>;

枚举类

/**
 * @brief C++11的枚举类
 * 下面等价于enum class Color2:int
 */
enum class Color2
{
    RED=2,
    YELLOW,
    BLUE
};
r2 c2 = Color2::RED;
cout << static_cast<int>(c2) << endl; //必须转!


可以指定用特定的类型来存储enum

enum class Color3:char;  // 前向声明

// 定义
enum class Color3:char 
{
    RED='r',
    BLUE
};
char c3 = static_cast<char>(Color3::RED);
  • 新的enum的作用域不在是全局的
  • 不能隐式转换成其他类型

引用与指针

引用指针
必须初始化可以不初始化
不能为空可以为空
不能更换目标可以更换目标

引用必须初始化,而指针可以不初始化。
我们在定义一个引用的时候必须为其指定一个初始值,但是指针却不需要。

int &r;    //不合法,没有初始化引用
int *p;    //合法,但p为野指针,使用需要小心

引用不能为空,而指针可以为空。
由于引用不能为空,所以我们在使用引用的时候不需要测试其合法性,而在使用指针的时候需要首先判断指针是否为空指针,否则可能会引起程序崩溃。

void test_p(int* p)
{
    if(p != null_ptr)    //对p所指对象赋值时需先判断p是否为空指针
        *p = 3;
    return;
}
void test_r(int& r)
{
    r = 3;    //由于引用不能为空,所以此处无需判断r的有效性就可以对r直接赋值
    return;
}

引用不能更换目标
指针可以随时改变指向,但是引用只能指向初始化时指向的对象,无法改变。

int a = 1;
int b = 2;

int &r = a;    //初始化引用r指向变量a
int *p = &a;   //初始化指针p指向变量a

p = &b;        //指针p指向了变量b
r = b;         //引用r依然指向a,但a的值变成了b

初始化列表与赋值

  • const成员的初始化只能在构造函数初始化列表中进行
  • 引用成员的初始化也只能在构造函数初始化列表中进行
  • 对象成员(对象成员所对应的类没有默认构造函数)的初始化,也只能在构造函数初始化列表中进行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值