目录
1.输出C++版本:cout << __cplusplus << endl;
2.Uniform Initialization(一致性初始化)
3.initializer_list(形参)
4.explicit
5.for循环的新用法
6.default和delete
7.Alias Template(模板化名)
8.模板模板参数
9.Type Alias(类型化名)
10.using的用法
11. 关键字 noexcept,override,final
1.输出C++版本:cout << __cplusplus << endl;
#include <iostream>
int main()
{
cout << __cplusplus << endl;
system("pause");
return 0;
}
老版的话会输出199711,支持c++11的话会输出201103
注:visual studio要手动打开c++11,在“解决方案资源管理器”右键自己的项目, 如“侯捷C++”(是总项目,不是项目中的某一头文件或源文件),按一下操作
【右击项目】–【选择属性】–【C/C++】–【语言】–【C++语言标准】,选择想要的标准即可
visual studio2019以上才支持C++11(好像是)
2.Uniform Initialization(一致性初始化)
C++在定义容器时,有的使用小括号,有的使用中括号,有的使用大括号,C++11及以后,统一使用大括号
#include <iostream>
#include <vector>
#include <complex>
using namespace std;
int values[] { 1,2,3 };
vector<int> v { 1,2,3 };
vector<string> cities {"beijing","shanghai","guangzhou"};
complex<double> c { 4.0, 3.0 }; //等价于 complex<double> c(4.0, 3.0);
3.initializer_list(形参)
如果函数的实参类型都相同 ,但个数不确定,使用initializer_list做形参,后面跟数据类型,如int,string等,initializer_list好像相当于链表
void printX(initializer_list<int> v1)
{
for (auto p = v1.begin(); p != v1.end(); ++p) {
cout << *p << typeid(p).name() << endl;
}
}
printX({1,2,3}); //函数调用
4.explicit
explicit
是一个关键字,用于修饰类的构造函数。当一个构造函数被声明为 explicit
时,它指定该构造函数不能用于隐式类型转换。这意味着在使用该构造函数创建对象时,必须使用显式的方式,而不能依赖于隐式的类型转换。
#include <iostream>
class MyClass {
public:
explicit MyClass(int x) {
value = x;
}
void printValue() {
std::cout << "Value: " << value << std::endl;
}
private:
int value;
};
int main() {
// 使用 explicit 构造函数的显式方式创建对象
MyClass obj1(10);
obj1.printValue();
// 下面这行代码将会导致编译错误,因为构造函数是 explicit 的
// MyClass obj2 = 20; // 错误:不能进行隐式类型转换
// 必须使用显式方式
MyClass obj3 = MyClass(20);
obj3.printValue();
return 0;
}
5.for循环的新用法
for(decl : coll){ // decl为声明,coll为容器
statement
}
示例1
for (int i : {1, 2, 3}) {
cout << i << endl;
}
示例2
vector<string> v1{ "beijing","shanghai","guangzhou" };
for (auto s : v1) {
cout << s << endl;
}
6.default和delete
default:在类中,如果你自行定义了一个构造函数,那么编译器就不会再给你一个默认的构造函数了,如果你在默认的构造函数上强制加上=default,就可以重新获得并使用默认的构造函数
delete:关键字用于禁用某个特殊成员函数。通过在声明中使用 delete
,你可以阻止编译器生成相应的函数,或者禁止使用某个函数。
class MyClass {
public:
// 显式使用默认构造函数
MyClass() = default;
// 使用默认的拷贝构造函数
MyClass(const MyClass&) = default;
// 使用默认的析构函数
~MyClass() = default;
};
class NonCopyableClass {
public:
// 禁用拷贝构造函数
NonCopyableClass(const NonCopyableClass&) = delete;
// 禁用拷贝赋值运算符
NonCopyableClass& operator=(const NonCopyableClass&) = delete;
};
7.Alias Template(模板化名)
模板化名,就是给模板起别名,使用using关键字,这个别名就代表那个容器,这个别名是支持传入参数的,即容器要放的数据类型,define和typedef不能代替模板化名,因为他们不支持传参
template <typename T>
using Vec = vector<T, allocator<T>>; //allocator<T>为分配器,一般可以省略
Vec<int> v1{2,3,5};
8.模板模板参数
模板中的参数类型T也可以是模板,如下:
template <typename T,template<class,T> class Container>
class my_class {
...
};
模板中的某个参数是模板,上图中第二行尖括号里的class后面的T省略了。当模板中的第二个参数是与第一个参数有关时,如上图,第二个参数是类模板,此时模板化名就派上用场了
9.Type Alias(类型化名)
类型化名,就是给类型起了一个别名,使用using关键字,此时完全等价于typedef,如下图左上角,都代表指向函数的指针,右下角都代表T为value_type类型
10.using的用法
c++中using主要有三大用法
第一类 用在打开标准库 如 using namespace std;
第二类 如下图我们类中的成员属性是Base中的,后面类中再出现此属性,就不用写Base::
第三类 就是我们刚才讲的模板化名和类型化名
11. 关键字 noexcept,override,final
1.noexcept():用在函数或成员函数后面,如果后面括号里的东西为真的话,此函数不会报错,如果省略括号,表示没有条件,此函数不会报错
2.override,final
override(重写):放在函数后面,告诉我们是重写这个函数,而不是重新定义一个函数
如下图,我们在父类中Base中有一个虚函数vfunc,我们在子类Derived1中想要重写这个虚函数,但是不小心把float写成了int,此时是重新定义了一个虚函数vfunc,相当于函数重载,但当我们后面加上override,如类Derived2中,告诉编译器我们是重写虚函数,此时如果不小心写错,如把float写成int,编译器会报错来提醒我们。
虚函数 参考:C++虚函数详解-CSDN博客
final:写在类后面,这个类是继承体中的最后一个,不能有别的类来继承他;写在成员函数后面,该成员函数不能被继承,但是该成员函数所在的类可以被继承
12.decltype
让编译器根据表达式推断出类型
int x = 5;
decltype(x) y = 10; // 使用 decltype 获取 x 的类型,并将其应用于变量 y
map<string,float> coll;
decltype(coll)::value_type elem; //等价于 map<string,float>::value_type elem;
注:每个容器都有value_type
与auto区别: decltype是C++11新增的一个关键字,和auto的功能一样,用来在编译时期进行自动类型推导。引入decltype是因为auto并不适用于所有的自动类型推导场景,在某些特殊情况下auto用起来很不方便,甚至压根无法使用。
auto varName=value;
decltype(exp) varName=value;
1. auto根据=右边的初始值推导出变量的类型,decltype根据exp表达式推导出变量的类型,跟=右边的value没有关系
2.auto要求变量必须初始化,这是因为auto根据变量的初始值来推导变量类型的,如果不初始化,变量的类型也就无法推导,而decltype不要求,因此可以写成如下形式decltype(exp) varName;