笔记 September 02, 2019

C++ 入门

Words count 6.4k Reading time 6 mins. Read count 0

基础

声明与定义

  • 为了支持分离式编译,C++将生命和定义区分开来,声明使得名字为程序所知,一个文件如果想要使用别处定义的名字必须包含对那个名字的声明,而定义负责创建与名字关联的实体。 变量只能被定义一次,但是可以被多次声明。
      extern int i;   //声明i,在其他文件中寻找i的定义  
      int j;          //声明并定义j
    
  • 建议当第一次使用变量时再定义他

引用

为对象起了另一个名字,即别名

    int ival = 1024;
    int &refVal = ival; 
    int &refVal2;       //错误,引用必须被初始化
  • 指针和引用都能提供对其他对象的间接访问但是引用本身并非一个对象,一旦定义引用无法重新绑定,但指针无此限制。

  • 通过引用代替指针,会使C++程序更容易阅读和维护

  • 当引用作为函数返回值时,函数可以作为左值。

void*指针

可存放任意对象的地址

const

const限定符

const对象一旦创建不能再改变,所以必须初始化。默认情况下,const对象仅在当前文件中有效,如果需要const对象在文件间共享,则对const对象不管是声明还是定义都添加extern关键字即可。

  1. 编译器可以利用这个事实进行优化。
  2. 它还有助于防止程序员编写修改初始化后不打算修改的对象的代码。

尽量使用常量引用,把函数不会改变的形参定义成普通的引用是一种比较常见的错误。因为

  1. 会给使用者误导,即函数可以修改它的实参的值。
  2. 会限制实参类型,即我们不能把const对象、字面值或者需要类型转换的对象传递给普通的引用形参。

指针和const

指向常量的指针不能用于改变其所指向对象的值
而常量指针不变的是指针本身而不是所指向的值

顶层const和底层const

  • 顶层const:表示指针本身是常量
  • 底层const:表示指针所指向的对象是一个常量

别名

typedef double wages;
using wages = double;

auto

必须有初始值

防止头文件重复包含

#ifndef SALES_DATA_H  
#define SALES_DATA_H
#include <string>
struct Sales_data {
    std::string bookNo;
    unsigned units_sold = 0;
    doubkle revenue = 0.0;
};
#endif

第一次包含Sales_data.h时,#ifndef检查结果为真,顺序执行后面的操作直到遇到#endif为止。

  • 头文件保护符很简单,习惯性地加上即可,没必要太在乎是否用到。

Vector

vector<T> v2(v1);
vector<T> v3(n, val);
vector<T> v4{a,b,c};

v.empty();
v.size();
v.push_back(t);
v1 = v2;
v1 = {a, b, c};
v1 == v2;
  • vector对象能够高效增长,所以不要提前声明容量。

  • vector不能采用下标形式添加元素,只能对确认已经存在的元素执行下标操作

数组

  • 在使用数组下标的时候,通常将其定义为size_t类型,size_t类型,size_t是一种机器相关的无符号整形,它被设计得足够大以便能表示内存中任意对象的大小。

使用引用形参返回额外信息

C++不支持多返回,可以用引用形参代替
在函数内部通过形参隐式地返回

main函数

int mian(int argc, char **argv){...}

第一个参数表示数组中字符串的数量,
第二个参数是数组,当使用argv中的实参时,记得可选实参从argv[1]开始,因为argv[0]保存程序的名字而非用户输入

可变形参

TODO

迭代器

TODO

数组指针和指针数组

int arr[10];
int *p1[10];            //含有10个指针的数组
int (*p2)[10] = &arr;   //指向含有10个整数的数组

尾置和decltype

  1. 使用尾置返回类型

    auto func(int i) -> int(*)[10];
    
  2. int odd[] = {1, 3, 5, 7, 9};
    int even[] = {0, 2, 4, 6, 8};
    decltype(odd) *arrPtr(int i){
     return (i % 2) ? &odd : &even;
    }
    

默认实参

string screen(sz ht=24, sz wid=80, char background=' ');

注意,一旦某个形参被赋予了默认值,后面所有的形参都必须有默认值

内联函数和constexpr函数

内联函数

inline char* dbtest(int a){
    return (i % 2) ? "a" : "b";
}

适合频繁调用的简单函数,可以减小调用开销

  • 定义在类内部的成员函数都是默认inline的

constexpr函数

TODO

  • 内联函数和constexpr函数通常定义在头文件中。

TODO

构造函数

  1. 无函数返回类型
  2. 初始值列表
  3. 花括号
    Sales_data() = default; //默认构造函数
    Sales_data(const std::string &s): bookNo(s) {}
    Sales_data(const std::string &s, unsigned n, double p):
    bookNo(s), units_sold(n), revenue(p*n) {}
    

struct和class

唯一的区别是默认的访问权限
struct:定义在第一个访问说明符之前的成员是public的
class:相反

友元

TODO
允许其他类或者函数访问它的非共有成员,方法是令其他类或者函数成为它的友元,只需增加一条以friend开始的函数声明语句即可。

类成员函数形参列表后的const

常量对象,以及常量对象的引用或指针都只能调用常量成员函数,类成员函数形参列表后的const就是把this指针由默认的常量指针变成常指针常量,然后常量对象就可以调用这些常量成员函数了。

mutable

mutable成员可以被const成员函数(任何成员函数)修改。

静态成员

静态成员被类的所有对象共享,存在于任何对象之外。
成员函数不通过作用域运算符就可以直接使用静态成员

动态内存

0%