前言
上周我们学习了【侯捷 C++ 面向对象高级开发】课程笔记以及个人注释(附带课程资源)
趁热打铁,继续学习。
这个系列教程主要讲述了Cpp11和14的新特性,只谈新东西。
这个教程我之前摸索学习了大概几节课,现在重新系统学习一下。
该课程笔记会记录我认为所有重要的、有用的知识点。
重要说明:
- 侯捷老师说得非常好,十分详细,一定要自己看看才可以知道我这个笔记在说什么。
- 很多东西我觉得比较泛用,如auto,range-based for,我就没有记下来。
课程资源
源自公众号:编程指北
链接: /s/19REVrk-_3lpQu_fUmRBRUw 密码: 7iup
或有条件也可以直接访问Youtube资源。
篇1 可变模板 Variadic Templates
之前学过。这种很方便做recursive function call
,也可以方便进行recursive inheritance
(如tuple)
- 多个重载版本的函数,会根据参数类型、顺序来调用。类型和顺序都很重要,要同时符合。
- 这里后面讲了很多细节,暂时没遇到,就先不写了。
//无参函数,可能是不需要的
void printX() {
}
//泛化的函数
template <typename T,typename... Types>
void printX(const T& firstArg, const Types&... args) {
cout << firstArg << endl;
//cout << sizeof...(args)<<endl; //包的大小
printX(args...); //一包输出
}
//更泛化的函数
template<typename... Types>
void printX(const Types&... args) {
}
int main() {
printX("hello", "chenliang", "liang",180);
return 0;
}
篇2 一致性初始化 Uniform Initialization
用{}
来一致性初始化,是一个通用的语法。编译器会做一个initializer_list,会关联(通过指针)到一个array<T,n>,T是类型,n是大小。但是需要初始化的类型支持{}
来一致性初始化。
int values[]{ 1,2,3 };
vector<int>v{ 2,3,3 };
如果使用空的{}
,则会有默认初值,如0或者nullptr
。但记住,它不允许narrowing initializations!
,如int x{5.3}
会报错。
篇3 初值列表 Initializer Lists
可作为函数的参数,可变参数,但必须是统一类型了。同时也可以作为构造函数。
比显示说明参数数量的更泛化一点。
篇7 Explicit for ctors taking more than one argument
多个参数要求explicit,即不可隐式转换(甚至不可以从initializer list
去隐式转换)。
当然我们可以从one argument开始理解。
Explicit for ctors taking only one argument
禁止隐式转换,上个课程有。
Class Complex{
explicit
Complex(int re,int im=0):....{....}
}
Complex c1(12,5);
Complex c2 = c1 + 5; //如果没有explict,则可以
篇9 =defualt, = delete
如果没有定义构造函数,那么编译器会自带一个默认构造函数,**但是如果自己定义了,默认构造函数就会丢掉。**如果我们还是希望保留,则用=defualt
来显式保留,但用=delete
显式删除。
class Zoo {
public:
Zoo(int i1, int i2) :d1(i1), d2(i2) {}
Zoo(const Zoo&) = delete;
Zoo(Zoo&&) = default;
Zoo& operator = (const Zoo&) = default; //copy
Zoo& operator = (const Zoo&&) = delete; //move
virtual ~Zoo() {}
private:
int d1, d2;
};
注意:如果类中包含了一个指针,则一般需要自己写BIG THREE。
No-Copy and Private-Copy
这里跟Effetivre C++讲的一样。
No-Copy(完全去掉了构造函数、赋值构造之类的函数)完全不能copy,PrivateCopy(把构造函数放在了private部分)可以被友元以及子类copy。
篇10 别名模板 Alias Template
使用using
关键字建立一个别名类型,以免类型十分赘余。
注意:别名无法做特化。
template <typename T>
using Vec = vector<T,MyAlloc<T>>;
Vec<int> coll; //它等于vector<int,MyAlloc<int>>;
这里视频讲得很深,我没感受到有什么用,就不拓展了。
篇12
Type Alias
类型的别名
using func = void(*)(int,int);
noexcept
设计者需要保证某个函数不会丢出异常。
noexcept(条件),即条件满足的情况下不会丢出异常。
void swap(x,y) noexcept(noexcept(x.swap(y))){
x.swap(y);
}
override
实现父类的虚函数,显式写出覆盖的语句声明。
final
跟java一样,不希望类或者方法继承,可以加final关键字。
篇13 decltype
获得一个变量的type。目前看不出来还有什么用。
篇14 lambda
是inline函数,是很实用的东西。
[x,&y(即传值还是传引用)](参数)mutable(决定引用的是否可以改变) throw -> returnType{...}
承上启下
上面讲了语言特性,以下讲标准库特性。
篇 23 Rvalue references and Move Semantics
右值引用,是一种新的引用类型,避免unnecessary copying
。当赋值右手边为rvalue,赋值左手边的值可以通过steal
来获取rvalue的值,而不需要内存分配。
- Lvalue: 可以出现在operator =左侧者。
- Rvalue:只能出现在operator=右侧者。
篇25 写一个move-aware class
很好的一个例子。
class MyString {
public:
static size_t DCtor; //累计default-ctor呼叫次数
static size_t Ctor; //累计ctor呼叫次数
static size_t CCtor; //累计copy-ctor呼叫次数
static size_t CAsgn; //累计copy-asgn呼叫次数
static size_t MCtor; //累计move-ctor呼叫次数
static size_t MAsgn; //累计move-asgn呼叫次数
static size_t Dtor; //累计dtor的次数
private:
char* _data;
size_t _len;
void _init_data(const char* s) {
_data = new char[_len + 1];
memcpy(_data, s, _len);
_data[_len] = '\0';
}
public:
//default constuctor
MyString() :_data(nullptr), _len(0) { ++DCtor; }
//constructor
MyString(const char* p) :_len(strlen(p)) {
++Ctor;
_init_data(p);
}
//copy constructor
MyString(const MyString& str) :_len(str._len) {
++CCtor;
_init_data(str._data);
}
//move constructor
MyString(MyString&& str) noexcept
:_data(str._data), _len(str._len) { //直接使用原来的指针
++MCtor;
str._len = 0;
str._data = nullptr;
}
//copy assignment
MyString& operator=(const MyString& str) {
++CAsgn;
//自我赋值检查
if (this != &str) {
if (_data) delete _data;
_len = str._len;
_init_data(str._data);
}
return *this;
}
//move assignment
MyString& operator=(MyString&& str) noexcept {
++MAsgn;
//自我赋值检查
if (this != &str) {
if (_data) delete _data;
_len = str._len;
_data = str._data;//直接使用原来的指针
str._len = 0;
str._data = nullptr;
}
return *this;
}
//dtor
virtual ~MyString() {
++Dtor;
if (_data) {
delete _data;
}
}
};
size_t MyString::DCtor = 0;
//...
后话
这里的知识普遍比较高级,实用性可能没有上一节课强,作为知识补充很不错。
看到这里基本算是cpp基础以及cpp11入门了,后面我将实际切入到项目当中进行学习。
欢迎留言交流,也欢迎私信交流。