1.继承,多态
2.虚函数
3.lambda表达式
Lambda 的语法形式如下:
[函数对象参数] (操作符重载函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}
函数对象参数取值:
- 空。没有任何函数对象参数。
- =。函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是值传递方式(相
当于编译器自动为我们按值传递了所有局部变量)。 - &。函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是引用传递方式
(相当于是编译器自动为我们按引用传递了所有局部变量)。 - this。函数体内可以使用 Lambda 所在类中的成员变量。
- a。将 a 按值进行传递。按值进行传递时,函数体内不能修改传递进来的 a 的拷贝,因为默认情况下函数是 const 的,要
修改传递进来的拷贝,可以添加 mutable 修饰符。 - &a。将 a 按引用进行传递。
- a,&b。将 a 按值传递,b 按引用进行传递。
- =,&a,&b。除 a 和 b 按引用进行传递外,其他参数都按值进行传递。
- &,a,b。除 a 和 b 按值进行传递外,其他参数都按引用进行传递。
操作符重载函数参数——标识重载的 () 操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如: (a, b))和按引用 (如: (&a, &b)) 两种方式进行传递。
mutable 或 exception 声明——这部分可以省略。按值传递函数对象参数时,加上 mutable 修饰符后,可以修改传递进来的拷贝(注意是能修改拷贝,而不是值本身)。exception 声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw(int)。
class CTest
{
public:
CTest() : m_nData(20) { NULL; }
void TestLambda()
{
vector<int> vctTemp;
vctTemp.push_back(1);
vctTemp.push_back(2);
{
for_each(begin(vctTemp),end(vctTemp),[](int v)
{
cout << v << endl;
});
//输出:1,2 无函数对象参数
}
{
int a = 10;
for_each(vctTemp.begin(), vctTemp.end(), [=](int v)
{ cout << v+a << endl; });
cout<<a<<endl;
//输出:11,12,10 以值方式传递作用域内所有可见的局部变量(包括this)
}
{
int a = 10;
int b=7;
for_each(vctTemp.begin(), vctTemp.end(), [&](int v)mutable{ cout << v+a+b << endl; a++; });
cout << a << endl;
cout << b << endl;
//输出:18,20,12,7 以引用方式传递作用域内所有可见的局部变量(包括this)
}
{
int a = 10;
for_each(vctTemp.begin(), vctTemp.end(), [a](int v)mutable{ cout << v+a << endl; a++; });
cout << a << endl;
//输出:11,13,10 以值方式传递局部变量a
}
{
int a = 10;
for_each(vctTemp.begin(), vctTemp.end(), [&a](int v){ cout << v+a << endl; a++;});
cout << a << endl;
//输出:11,13,12 以引用方式传递局部变量a
}
{
for_each(vctTemp.begin(), vctTemp.end(), [this](int v){ cout << v+m_nData << endl; });
//输出:21,22 传递this
}
{
for_each(vctTemp.begin(), vctTemp.end(), [&](int v){ cout << v+m_nData << endl; m_nData++;});
cout<<m_nData<<endl;
//输出:21,23,22 以引用方式传递作用域内所有可见的局部变量(包括this)
}
{
int a = 10;
int b = 15;
for_each(vctTemp.begin(), vctTemp.end(), [=, &b](int v){ cout << v+a+m_nData << endl; b++; m_nData++;});
cout<< b << endl;
cout<<m_nData<<endl;
//输出:33,35,17,24 除b和this按引用传递外,其他均按值传递
}
{
for_each(vctTemp.begin(), vctTemp.end(), [](int &v){ v++; });
for_each(vctTemp.begin(), vctTemp.end(), [](int v){ cout << v << endl; });
//输出:2,3 操作符重载函数参数按引用传递
}
}
private:
int m_nData;
};
Mac使用c++11特性的编译方式:g++ -std=c++11 A.cpp
4.智能指针
5.右值引用
6.一些关键字
extern
extern置于变量或函数前,用于标示变量或函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。它只要有两个作用:
- 当它与“C”一起连用的时候,如:extern "C" void fun(int a,int b);则告诉编译器在编译fun这个函数时候按着C的规矩去翻译,而不是C++的(这与C++的重载有关,C++语言支持函数重载,C语言不支持函数重载,函数被C++编译器编译后在库中的名字与C语言的不同)
- 当extern不与“C”在一起修饰变量或函数时,如:extern int g_Int;它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块或其他模块中使用。记住它是一个声明不是定义!也就是说B模块(编译单元)要是引用模块(编译单元)A中定义的全局变量或函数时,它只要包含A模块的头文件即可,在编译阶段,模块B虽然找不到该函数或变量,但它不会报错,它会在连接时从模块A生成的目标代码中找到此函数。
static
修饰局部变量
static修饰局部变量时,使得被修饰的变量成为静态变量,存储在静态区。存储在静态区的数据生命周期与程序相同,在main函数之前初始化,在程序退出时销毁。static修饰局部变量是改变了存储位置和初始化方式【static解决问题:占用大量栈空间,函数多次执行可以基于前一次的执行结果】修饰全局变量
全局变量本来就存储在静态区,因此static并不能改变其存储位置。但是,static限制了其链接属性。普通全局变量可以被程序内所有文件访问,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。被static修饰的全局变量只能被该包含该定义的文件访问(即改变了作用域)。【static解决问题:不同文件可以定义重名的全局变量,防止被误引用和操作】修饰函数
static修饰函数使得函数只能在包含该函数定义的文件中被调用。对于静态函数,声明和定义需要放在同一个文件夹中。修饰成员变量
用static修饰类的数据成员使其成为类的全局变量,会被类的所有对象共享,包括派生类的对象,所有的对象都只维持同一个实例。 因此,static成员必须在类外进行初始化(初始化格式:int base::var=10;),而不能在构造函数内进行初始化,不过也可以用const修饰static数据成员在类内初始化。修饰成员函数
用static修饰成员函数,使这个类只存在这一份函数,所有对象共享该函数,不含this指针,因而只能访问类的static成员变量。静态成员函数是可以独立访问的,也就是说,无须创建任何对象实例就可以访问。例如可以封装某些算法,比如数学函数,如ln,sin,tan等等,这些函数本就没必要属于任何一个对象,所以从类上调用感觉更好,比如定义一个数学函数类Math,调用Math::sin(3.14);还可以实现某些特殊的设计模式:如Singleton;
最重要的特性:隐藏——当同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。
【注意】不可以同时用const和static修饰成员函数。
C++编译器在实现const的成员函数的时候为了确保该函数不能修改类的实例的状态,会在函数中添加一个隐式的参数const this*。但当一个成员为static的时候,该函数是没有this指针的。也就是说此时const的用法和static是冲突的。我们也可以这样理解:两者的语意是矛盾的。static的作用是表示该函数只作用在类型的静态变量上,与类的实例没有关系;而const的作用是确保函数不能修改类的实例的状态,与类型的静态变量没有关系。因此不能同时用它们。
const
- 定义变量为只读变量,不可修改
- 修饰函数的参数和返回值(后者应用比较少,一般为值传递)
- const成员函数(只需要在成员函数参数列表后加上关键字const,如char get() const;)可以访问const成员变量和非const成员变量,但不能修改任何变量。在声明一个成员函数时,若该成员函数并不对数据成员进行修改操作,应尽可能将该成员函数声明为const成员函数。
- const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.即对于class A,有const A a;那么a只能访问A的const成员函数。而对于:A b;b可以访问任何成员函数。
使用const关键字修饰的变量,一定要对变量进行初始化
【插播:const和static使用原则】瞎写的
- 当一个局部变量在下次执行时,仍需要参考上次的值,或者会比读写很多次占用大量栈空间,这时候我们可以将其声明为静态局部变量。
- 全局变量也可以只初始化一次并且全局参考,那和静态局部变量有什么区别?全局变量作用域为整个类/命名空间/程序,而静态局部变量作用域为定义它的函数体。
- 为了允许多个文件中出现同名的全局变量,可以使用静态全局变量改变其作用域(比如包含对应头文件)
- const和static不能同时修饰成员函数,因为static类型的成员函数不带有this指针。
volatile
用来修饰变量的,表明某个变量的值可能会随时被外部改变,因此这些变量的存取不能被缓存到寄存器,每次使用需要重新读取。
explicit
避免类构造函数的隐式自动转换(没有用explicit声明,就默认是implicit),允许隐式自动转换的类初始化的时候会把自定义类型隐式转换为类类型,造成一些语法理解的歧义。explicit关键字介绍,有示例代码
mutable
为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。
auto
根据初始值自动推断变量的数据类型,定义时必须有效初始化哈。有的编译器不支持auto关键字。
*_cast
类型转换
- const_cast:删除const变量的属性,用于改变常量的值
- dynamic_cast:将一个父类对象的指针转换为子类对象的指针或引用
- reinterpret_cast:将一种类型转换为另一种不同的类型
- static_cast:静态转换,任何转换都可以用它,但他不能用于两个不相关的类型转换
friend
友元。使其不受访问权限控制的限制。例如,在1个类中,私有变量外部是不能直接访问的。可是假如另外1个类或函数要访问本类的1个私有变量时,可以把这个函数或类声明为本类的友元函数或友元类。这样他们就可以直接访问本类的私有变量。
union
联合体。注意联合体与结构体的区别,联合体是多个成员共用同一内存,联合体占内存大小为最长的成员占用内存大小,对联合体成员赋值会覆盖之前的其他成员值。而结构体中不同成员各自占有内存,成员赋值互不影响。
extern
- 当出现extern “C”时,表示 extern “C”之后的代码按照C语言的规则去编译;
- 当extern修饰变量或函数时,表示其具有外部链接属性,即其既可以在本模块中使用也可以在其他模块中使用。
register
提示编译器尽可能把变量存入到CPU内部寄存器中。
operator
和操作符连用,指定一个重载了的操作符函数,比如,operator+。
export
使用该关键字可实现模板函数的外部调用。对模板类型,可以在头文件中声明模板类和模板函数;在代码文件中,使用关键字export来定义具体的模板类对象和模板函数;然后在其他用户代码文件中,包含声明头文件后,就可以使用该这些对象和函数。【没用过】
using
- 在当前文件引入命名空间,例using namespace std;
- 在子类中使用,using声明引入基类成员名称。
constexpr
参考文档
- 1.C++之Lambda表达式
- 2.**C++面试常见问题
- 3.C++之单例模式
- 4.C++关键字
- 5.** 面试中的C++单例模式