仅做个人学习《C++ Primer》的一点儿记录。
2. 变量和基本类型
int* p1, p2; // p1: pointer, p2: int;
---
int i = 0;
decltype(i) i2=0; // 获得i的类型;
---
vector<int> vec(10); // vec 有10个int元素,初始为0;
vector<int> vec(10, 1); // 10个元素,均为1;
vector<int> vec{10}; // = vector<int> vec={10}; 1个元素,为10;{}:初始化列表。
---
int vec[]={1,2,3,4};
int *pb = begin(vec), *pe = end(vec); // begin/end为关键字,获得数组的起始终止的指针。
---
// 关于 constexpr
constexpr int func(int i){ return i+5; }
int a = func(2); // 正确~
int i = 2; int a = func(i); // 错误
- 头文件不建议包含 using 声明,避免包含时的名称冲突
- size_t 类型:机器相关的无符号类型,足够大,可以表示任意对象的大小;建议使用数组下标时采用
constexpr
常量表达式,即函数/表达式,无需计算,在编译时即可获得结果;优秀的编译器会自动进行优化。
6. 函数
- 函数形参使用引用,避免拷贝;const限制避免修改
constexpr
函数与内联函数,建议放到头文件assert
是“预处理宏”,定义在cassert
中,由预处理器处理,而不是编译器;
cout << __FILE__ << __func__ << __LINE__; // 指代当前:文件名、函数名和行数,用于debug
---
//函数指针
int (*pf) (int a, int b);
int compareInt(int a, int b);
pf = compareInt; // or: pf = &compareInt;
// 调用:
bool r1 = pf(3,5); // or: bool r1 = (*pr)(3,5);
7. 类
- 定义在类内部的函数是隐式的inline函数;如果定义在外部,则不是内联
- 成员函数通过一个名为
this
的额外的隐式参数来访问调用的对象,this
是一个常量指针,例如:
total.sum();
Data::sum(&total);
const
成员函数,在函数名后面加上const
关键字,才可以让const
成员变量进行调用,表示这个函数不会修改变量。- return一个
*this
(this解引用)可以获得该函数的对象 istream/ostream
是IO类,不能进行拷贝,只可以进行引用来实现传参- 合成的默认构造函数:当没有显示的构造函数时,编译器自行创建,变量初始化的依据:1. 首先依据变量在类内的初始值,2. 根据默认初始化
struct/class
:仅仅默认访问权限不同。对于struct,第一个访问说明符(public/private)之前的成员是public,class的是private- 建议:对于公共代码使用私有功能函数。即在public中定义一个display,调用private中的do_display,这样的好处:1. 便于在do_display中添加debug功能;2. 便于后续在private中的do_display中进行扩充;在public中进行定义,形成内联,不会增加额外开销
- 类的前向声明:声明有一个类,但不在这里进行定义,是一个“不完全类型”。
- 类中变量名称查找顺序:1. 成员函数内;2. 类中;3. 成员函数定义之前的作用域
构造函数
- 构造函数的初始化和赋值不同,在有
const
修饰时,必须采用初始化的方式 - 构造函数中初始化列表的初始化顺序:按照类中的定义顺序,而不是列表的顺序;
- 构造函数的隐式转化:实参可以经过1步转化,变为形参,例如:
item.combine(string("123")); // 正确。显示转为string,隐式转为Sales_Data
item.combine(Sales_Data("123")); // 正确。隐式转为string,显示转为Sales_Data
item.combine("123"); // 错误。经过了两次转化
- 为避免隐式转化,构造函数增加
explicit
关键词,加以阻止。添加在“声明”,不能加在“定义”处。且explicit
定义的构造函数,只能用于直接初始化(小括号),而不能采用赋值初始化 - 类的静态成员,采用
static
关键字,将这个静态成员与“类”而不是“实例”关联在一起,存在于任何对象之外。必须在类的外部定义与初始化所有静态成员
----
// 类中
Sales_Data() = default; // 显示表明,我们需要编译器进行默认的构造行为。
// 如果类有了其他构造函数,不使用这一行,则这个类就没有了默认构造函数
Sales_Data() = delete; // 显示的禁止默认构造函数
---
// 一个返回*this的成员函数实例:
Student &Student::setName(string nn){
name = nn; // this->name = nn;
return *this; // 这样便修改了Student.name的值
}
//调用:
Student std1;
std1.setName("LarryDong");
// 要注意返回的一定是 引用&,否则只改变了临时的副本,而不能修改std1的值
小结
2020年8月4日,感觉随着C++的使用,又看懂了一些当时搞不懂的内容。例如静态成员变量,在SLAM中常用作id进行计数,也必须定义在类外。同时对:explicit
, constexpr
,以及 return *this
有了清楚地了解。