《C++11/14高级编程Boost程序库探秘》之第1章全新的C++语言(二)
1.4面向过程编程
1.4.1空指针
nullptr明确表示空指针概念,可以完全替代NULL,它可以隐式转化为任意类型的指针,也可以与指针进行比较运算,但决不能转化为非指针的其他类型。比如,10>=nullptr会提示编译错误,不能与整数等类型进行运算。
在编写代码时,应总使用nullptr来初始化或比较指针,尽量避免使用NULL宏。
1.4.3新式for循环
[root@localhost C++11]# cat newfor.cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int a[] = {2,3,5,7};
vector<int> v = {253,874};
for(auto x : a) //使用auto推导类型变量
{
cout<<x<<","; //直接访问元素,无须解引用
}
for(const auto& x : v)
{
cout<<x<<",";
}
return 0;
}
[root@localhost C++11]# g++ newfor.cpp -o newfor -std=c++11
[root@localhost C++11]# ./newfor
2,3,5,7,253,874,
1.4.4 新式函数声明
允许返回值类型后置,格式如下:
auto func(...) -> type {...}
首先,函数返回值处必须使用auto来占位;
其次,函数名后需要使用->type的形式来声明真正的返回值类型。
之所以采用这种方式是因为在泛型编程的时候,函数返回值的类型可能需要由实际的参数来决定,所以需要将返回值类型的声明延后。
1.5面向对象编程
1.5.1 default
允许显示地声明类的缺省构造/析构等特殊成员函数,不仅能够明确地表示代码意图,而且可以让编译器更好地优化代码。
class default_demo
{
public:
//显示指定构造函数和析构函数使用编译器的缺省实现
default_demo() =default;
~default_demo() =default;
//显示指定拷贝构造函数和拷贝赋值函数使用编译器的缺省实现
default_demo(const default_demo&) =defualt;
default_demo& operator=(const default_demo&) =default;
//显示指定转移构造函数和转移赋值函数使用编译器的缺省实现
default_demo(default_demo&&) =default;
default_demo& operator=(default_demo&&) =default;
}
1.5.2 delete
显示的禁用某些函数——通常是类的构造函数和拷贝构造函数,以阻止对象的拷贝。
[root@localhost C++11]# cat deletedemo.cpp
#include <iostream>
#include <vector>
using namespace std;
class delete_demo
{
public:
delete_demo() =default;
~delete_demo() = default;
//显示禁用拷贝构造函数和拷贝赋值函数
delete_demo(const delete_demo&) =delete;
delete_demo& operator=(const delete_demo&) = delete;
}
int main()
{
delete_demo d1;
delete_demo d2 = d1;//无法赋值,发生编译错误
return 0;
}
delete不仅可以作用于类成员函数,也可以作用于普通函数,禁用某些形式的重载。
1.5.3 override
显式地标记虚函数的重载,派生类里的成员函数名后如果使用了override修饰,那么它必须是虚函数,而且签名也必须与基类的声明一致,否则会导致编译错误。
[root@localhost C++11]# cat overridedemo.cpp
#include <iostream>
#include <memory>
using namespace std;
class base
{
public:
virtual ~base() = default;
virtual void f() = 0;//纯虚函数
virtual void g() const { cout<<"base:g func"<<"\n"<<endl; };//虚函数,const修饰
void h(){ cout<<"base:h func"<<"\n"<<endl; };
};
class derived : public base
{
public:
virtual ~derived() = default;
void f() { cout<<"derived:f func"<<"\n"<<endl; }//虚函数重载
void g() { cout<<"derived:g func"<<"\n"<<endl; }//不是虚函数重载,签名不同,无const修饰
void h() { cout<<"derived:h func"<<"\n"<<endl; }//不是虚函数重载,是覆盖
};
int main()
{
unique_ptr<base> p(new derived);
p->f();
p->g();//调用了基类的g函数,与初衷不符
p->h();//调用了基类的h函数,与初衷不符
return 0;
}
[root@localhost C++11]# g++ overridedemo.cpp -o overridedemo -std=c++11
[root@localhost C++11]# ./overridedemo
derived:f func
base:g func
base:h func
使用override后,代码修改如下:
[root@localhost C++11]# cat overridedemo_new.cpp
#include <iostream>
#include <memory>
using namespace std;
class base
{
public:
virtual ~base() = default;
virtual void f() = 0;//纯虚函数
virtual void g() const { cout<<"base:g func"<<"\n"<<endl; };//虚函数,const修饰
void h(){ cout<<"base:h func"<<"\n"<<endl; };
};
class derived : public base
{
public:
virtual ~derived() = default;
void f() override { cout<<"derived:f func"<<"\n"<<endl; }//override明确是虚函数重载
void g() const override { cout<<"derived:g func"<<"\n"<<endl; }//有const修饰,override明确是虚函数重载
void h() override { cout<<"derived:h func"<<"\n"<<endl; }//非虚函数重载,调用override,编译报错
};
int main()
{
unique_ptr<base> p(new derived);
p->f();
p->g();
p->h();
return 0;
}
[root@localhost C++11]# g++ overridedemo_new.cpp -o overridedemo_new -std=c++11
overridedemo_new.cpp:20:10: error: ‘void derived::h()’ marked ‘override’, but does not override
20 | void h() override { cout<<"derived:h func"<<"\n"<<endl; }//非虚函数重载,调用override,编译报错
| ^
1.5.4 final
在类名后使用final,显式地禁止类被继承,即不能再右派生类。
在虚函数后使用final,显式地禁止该函数在子类里再被重载。
final和override混用,更好的标记类的继承体系和虚函数。
[root@localhost C++11]# cat finaldemo.cpp
#include <iostream>
#include <memory>
using namespace std;
class base
{
public:
virtual ~base() = default;
virtual void f() = 0;//纯虚函数
virtual void g() = 0;//纯虚函数
};
class derived : public base
{
public:
virtual ~derived() = default;
void f() override final { cout<<"derived:f func"<<"\n"<<endl; }//虚函数重载,使用final,不能再被重载
void g() override { cout<<"derived:g func"<<"\n"<<endl; }//虚函数重载,派生类还可以继续重载
};
class child final : public derived
{
public:
void f() override {}//错误,f()不可再被重载
void g() override {}//g仍然可以被重载
};
class end : public child //错误,child类不能被继承
{
};
int main()
{
return 0;
}
[root@localhost C++11]# g++ finaldemo.cpp -o finaldemo -std=c++11
finaldemo.cpp:24:10: error: virtual function ‘virtual void child::f()’ overriding final function
24 | void f() override {}//错误,f()不可再被重载
| ^
finaldemo.cpp:17:10: note: overridden function is ‘virtual void derived::f()’
17 | void f() override final { cout<<"derived:f func"<<"\n"<<endl; }//虚函数重载,使用final,不能再被重载
| ^
finaldemo.cpp:28:7: error: cannot derive from ‘final’ base ‘child’ in derived type ‘end’
28 | class end : public child //错误,child类不能被继承
1.6 泛型编程
1.6.1 类型别名
使用using alias = type的形式为类型起别名,例如:
using int64 = long;
using llong = long long;
1.6.2 编译器常量
constexpr int kk = 1024;
constexpr long giga()//编译期常量函数
{ return 1000*1000*1000;}
1.6.3 静态断言
C语言提供assert,但泛型编程主要工作在编译期,assert无法起作用。
C++11/14增加了关键字static_assert,是编译期断言,基本用法是
static_assert(condition,message)
如果condition表达式在编译期的计算结果为false,那么编译期会报错,并给出message提示。
1.6.4 可变参数模板
可变参数模板使用省略号...来声明不确定数量的参数,形式如下:
template<typename ... T> class some_class {};//模板类
template<typename ... T>void some_fun() {};//模板函数
模板参数列表里的typename ... T声明了一个具有不确定数量参数的模板列表——模板参数包,其数量可以是0,1或者更多,可以使用sizeof...(T)的方式得到具体数量。
声明了可变模板参数后,还需要解开包才能使用,直接在类型名后用...即可,例如:
template<typename ... T>
class variadic_class
{
using type = x<T...>;
};
template<typename ... Args>
void variadic_func(Args ... args)
{ cout<<sizeof...(Args)<<endl;}
《C++11/14高级编程Boost程序库探秘》之第1章全新的C++语言(二)学习记录
原文:https://www.cnblogs.com/snake-fly/p/12614099.html