C++学习笔记

C++学习笔记

C++里面比较重要、或比较难记住、或比较复杂的一些知识点
一些太简单的就没写在这里了
页码来自C++ Primer Plus(第6版)中文版

函数模版

格式

template <typename T>
T f(T a);
//另一种写法
template <class T>
T f(T a);

templa <class t1,  class t2> f(t1 a,  t2 b);
  • 函数模版重载与普通函数重载一样

显式实例化 p288

  • 使用模版生成函数定义
template void swap<int> (int,  int);
//另一种写法, 因为编译器可以从后面的参数自动判断类型,所以可省略
template void swap<> (int,  int);

具体化 p288

完全具体化
  • 不要使用模版生成的定义, 而应使用专门的函数定义
template <> void swap<int> (int,  int);
template <> void swap<> (int,  int);
  • 可以省去函数名后面尖括号里的类型名字
  • 具体化template后面有一个空尖括号
  • 实例化还必须提供定义, 另外定义和在声明处定义均可
部分具体化
  • 部分限制模版通用性
template <class T1,  class T2>
void tf(T1 a,  T2 b)
{
    cout << a + b << endl;
}

template <class T1>
void tf(T1 a,  int b)
{
    cout << "fuck";
    cout << a + b << endl;
}
  • 但全部类型都被指定了(完全具体化), 前面的尖括号就变空了, 这就是完全具体化前面空尖括号的意思
非类型模版参数
template <class T1,  int n>
void f(T1 a)
{
    cout << a + n << endl;
}
  • 调用时必须强制选择f<double, 10>(10.10);否则会报错
  • 这个好像并没有什么用, 看完类模版的非类型参数用函数模版试了一下, 发现也行

匹配 p289

  • 编译器在选择函数是根据下面这三个的顺序寻找的
    1. 最匹配 (完全匹配>提升转换>标准转换(int->char, long->double)>用户定义的转化)
    2. 非模版 (如果多个函数匹配程度相同, 非模版函数优先)
    3. 最具体

强制选择 p293

Swap<>(a, b); 强制使用模版函数(而不是非模版函数)
Swap<int>(a, b); 强制使用int实例化的模版函数

关键字 decltype(c++11) p295

decltype( expression ) var; 如果expression
为表达式, var与结果值类型相同
为函数, var与函数返回值类型相同(包括const, &)
如果expression用括号括起来了
var类型参考上面两条, 再变成引用
int a;
decltype( (a) ) b;//b为int&

后置返回类型(c++11) p297

  • 如果返回类型需要由参数决定, 但返回类型在参数之前, 此时参数类型还没确定, 只能用后置返回类型
auto f(int a,  double b) ->double;
template <class p,  class t> auto f(p a,  t b) ->decltype(a+b);

存储说明符

  • auto(c++11后不再是说明符), register, static, extern, thread_local, mutable

register p309

c及c++11之前:
建议编译器使用寄存器存储变量
c++11:
不再有上面的功能, 显式指出变量为自动的, 避免使之前的代码非法

static 变量链接性, 作用域, 持续性 p310

存储描述 持续性 作用域 链接性 声明
自动 自动 代码块 代码块中
寄存器 自动 代码块 代码块register
静态无连接性 静态 代码块 代码块static
静态外部链接性 静态 文件 外部 函数外, 不加static
静态内部链接性 静态 文件 内部 函数外, 加static
静态变量自动初始化为0, 指针初始化为空指针

extern 要使用其他文件中的变量, 必须用extern在该文件中用extern声明

file1 : int a;
file2 : extern int a;

mutable

  • 在类或结构体中使用, 表明即使这个类的对象为const, 这个值也能被修改
struct d
{
    mutable int a;
    int b;
};
const d a;
a.a = 20;//依旧可以被修改
a.b = 20;//非法

cv限定符 consst, volatile p317

const 内部链接性 p318

  • const 类型的全局变量为内部链接性, 不与其他文件共享
  • 可以使用extern使其变成外部链接性
    extern const int a;

volatile

  • 表明即使程序代码没有对这个变量进行修改, 它的值仍然可能会改变
    硬件或其它程序可能会对它进行修改

函数链接性

static 表明函数只在这个文件中可见
static int f(int a);

语言链接性 p319

extern "C" void f(int a);
extern "C++" void f(int a);

定位new运算符 p321

  • 需要包含new头文件
  • 指定要使用的内存位置(普通new在堆中分配内存)
  • 不需要使用delete释放内存
char buf[1000];
double * pd = new (buf) double[12];

类与对象

类声明大括号后面要分号
  • 编译器会自动添加{};, 导致很容易忘记后面有分号, 遇上不会自动补全的编辑器就容易忘记敲
  • 结构也一样

inline

  • 在类声明中定义的函数都自动成为内联函数(如果可以的话)
  • 也可以在声明中加inline使其成为内联函数

对象数组初始化

class A
{
//定义
};
A a[10] = 
{
    A(arg1,  arg2);
    A();
    //可对不同元素使用不同构造函数
    ...
}

作用域为类的常量 const p372

  • 不能使用const, 因为类声明的时候没有给它提供存储空间, 只有创建对象时候才有空间
    虽然可以在类声明里定义一个const int a;不会报错
    但只要你在类声明里使用这个a, 就会报错, 因为这个时候(声明时)还不存在a
    可使用 static const 或者 enum
  • 在类那使用非静态const常量时候, 只能在声明处给出它的值或创建对象时使用构造函数设置它的值, 之后便不能再更改

类中的static静态变量

  • 在类中声明了一个static静态变量,使用它前,必须显式定义它
    例如:
class A
{
   
private:
    static int a[10];
};
//显式定义
int A::a[10];
//如果没有显式定义, 会出现:undefined reference to `A::a|
enum
  • enum class egg{small, medium, ...} class限定作用域在类内, 防止出现两个small等等情况冲突
  • enum class : short egg ... 显式指定egg enum底层为short, 不然底层由不同实现决定(不同编译器会出现不同的情况)

运算符重载 p387

  • 注意事项
    1. 不能违反运算符原来的句法规则(参数个数不能改变)
    2. 不能改变运算符优先级
    3. 不能创建新的运算符
不能重载的运算符:

sizeof
. (成员)
.* (成员指针)
:: (作用域解析符)
?: (三目运算符)
typeid (RTTI运算符)
const_cast dynamic_cast reinterpret_cast static_cast (强制类型转换运算符)

只能通过成员函数重载的运算符

=
()
[]
->

类的强制与自动类型转换 p413

  • 接受一个参数(只有一个参数或对第一个参数之后的参数提供默认值)的构造函数可以实现类的自动类型转换
关键字explicit
  • 关闭隐式转换
    explicit ClassName() {}
二次转换
  • 当不存在二义性的时候, 会自动进行二次转化
class A
{
    A(double a) .....
};

A a;
a = 10;//会自动进行二次转化, 合法
  • 如果还有一个A(long)构造函数就会出现二义性, 不会自动进行二次转换
转换函数(将类转化成其它类型)

operator type();
例如: 类的成员函数operator int() const; 可以讲类转换成int
同样可以使用 explicit关闭隐式转换

复制构造函数 p432

  • 将一个对象复制到新创建的对象中去
  • 只在新建一个对象并且初始化为同类对象的时候才会被调用
  • 默认复制构造函数只进行浅复制(例如只复制指针, 而不复制指针指向的内存空间)

赋值运算符

  • operator =
    默认复制运算符也和默认构造函数一样, 只进行浅复制

静态 类成员函数 static p441

  • 可以将成员函数声明为静态
  • 静态成员函数不能通过对象调用(编译器实测可以, 但是C++PP说不可以, 想想通过对象调用静态函数也没什么意义, 静态函数不能访问非静态成员), 只能通过类名和作用域解析运算符::来调用它
    (如果该函数是public)
class A
{
    static int f();
};
A a;
a.f(); //错误(编译器实测可以, 但是C++PP说不可以, 想想通过对象调用静态函数也没什么意义, 静态函数不能访问非静态成员)
A::f(); //正确
  • 静态成员函数只能访问静态成员

在构造函数中使用new的注意事项

  • new一个变量建议使用 int *a = new int[1];(以int为例)
    这样delete的时候使用delete [] a;
  • 如果使用new int;delete的时候却使用了delete会出问题

继承

基类指针或引用可以直接指向派生类对象

  • 基类指针只能调用基类成员, 即使指向派生类对象, 也不能调用派生类成员

虚函数 关键字virtual p493

  • 使用关键字virtual, 通过指针或引用调用成员时候, 将根据指针或引用指向的对象决定调用哪个方法
  • 否则, 将根据指针或引用的类型决定
  • virtual 应该在基类中使用, 因为需要使用虚函数特性的情况都是使用基类指针或引用调用方法
  • 派生类重新定义的虚函数前也可以加上virtual, 但不是必要的
  • 可以使用override(C++11)显式指出派生类重新编写的基类虚函数
虚析构函数
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值