IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 11 常用特性(一) -> 正文阅读

[C++知识库]C++ 11 常用特性(一)

C++ 11 常用特性(一)

1. 原始字面量

C++11中添加了定义原始字符串的字面量,定义方式为:

R"xxx(原始字符串)xxx"其中()两边的字符串可以省略。原始字面量R可以直接表示字符串的实际含义,而不需要额外对字符串做转译或链接等操作。

void rawliteral()
{
	string s1 = "D:\hello\world\test.Text" ;
	cout<<s1<<endl;

	string str = R"(D:\hello\world\test.Text)";
	cout<<str<<endl;
} 

2. nullptr

? 在C++程序开发中,为了提高程序的健壮性,一般会在定义指针的同时完成初始化操作,或者在指针的指向尚未明确的情况下,都会给指针初始化为NULL,避免产生野指针(没有明确指向的指针,操作这种指针极可能导致程序发生异常)。nullptr专用于初始化空类型指针,不同类型的指针变量都可以使用nullptr来初始化:

int main()
{
    int *ptr1 = nullptr;
    char *ptr2 = nullptr;
    double *ptr3 = nullptr;
    void *ptr5 = nullptr;
}

3. constexpr常量表达式修饰符

? C++程序从编写完毕到执行分为四个阶段:预处理、编译、汇编、链接 4个阶段,得到可执行程序之后就可以运行了。需要强调的是,常量表达式和非常量表达式的计算实际不同,非常量表达式只能在程序运行阶段计算出结果,但是常量表达式的计算往往发生在程序的编译阶段,这可以极大提高程序的执行效率,因为表达式只需要在编译阶段计算一次,节省了每次程序运行时都需要计算一次的时间。
? C++11中添加了 constexpr 关键字用来表达常量表达式,在使用中,建议将constconstexpr的功能区分开,即凡是表达“只读”语义的场景都是用const,表达常量语义用constexpr

const int m = f(); //不是常量表达式,m的值只有运行才知道
const int i = 520; //常量表达式
const int j = i+1; //常量表达式

constexpr int i = 520 ; //常量表达式
constexpr int j = i+1;

//同时需要注意,constexpr只能修饰C++内置类型的数据,不能修饰自定义数据类型,类似(class,struct)

常量表达式函数

为了提高C++程序的执行效率,我们可以将程序中值不需要发生变化的变量定义为常量,也可以使用constexpr修饰函数的返回值,这种函数称为常量表达式函数,这些函数主要包括以下几种:普通函数\类成员函数、类构造函数、模板函数

  • 修饰函数

constexpr修饰函数,必须要满足以下几个条件:

  1. 函数必须要有返回值,并且return返回的表达式必须是常量表达式:
// error,没有返回值,不是常量表达式函数
constexpr void func1()
{
    int a = 100;
    cout << "a: " << a << endl;
}

// error,返回值不是常量表达式,不是常量表达式函数
constexpr int func1()
{
    int a = 100;
    return a;
}
2. 函数在使用之前,必须有对应的定义语句
constexpr int func1();
int main()
{
    constexpr int num = func1();	// error
    return 0;
}

constexpr int func1()
{
    constexpr int a = 100;
    return a;
}
  1. 整个函数的函数体中,不能出现非常量表达式之外的语句(using\typedef\static_asset断言、return语句除外)
// error for循环只有在程序运行之后才能得到i的值,所以不满足constexpr修饰函数的条件
constexpr int func1()
{
    constexpr int a = 100;
    constexpr int b = 10;
    for (int i = 0; i < b; ++i)
    {
        cout << "i: " << i << endl;
    }
    return a + b;
}

// ok
constexpr int func2()
{
    using mytype = int;
    constexpr mytype a = 100;
    constexpr mytype b = 10;
    constexpr mytype c = a * b;
    return c - (a + b);
}
  • 修饰模板函数

    C++11 语法中,constexpr 可以修饰函数模板,但由于模板中类型的不确定性,因此函数模板实例化后的模板函数是否符合常量表达式函数的要求也是不确定的。如果constexpr 修饰的模板函数实例化结果不满足常量表达式函数的要求,则 constexpr会被自动忽略,即该函数就等同于一个普通函数。

struct Person {
	const char* name;
	int age;
};

template<typename T>
constexpr T display(T t) {
	return t;
}

void constexprtemplate() {
	struct Person p {"zsj",10 };
	struct Person ret = display(p);
	cout << ret.name << ret.age << endl;

	constexpr int ret1 = display(250);
	cout << ret1<<endl;

	constexpr struct Person p1 { "alj", 9 };
	constexpr struct Person p2 = display(p1);

	cout << p2.name << p2.age << endl;
}

struct Person ret = dispaly(p); 由于参数p是变量,所以实例化后的函数不是常量表达式函数,此时 constexpr是无效的
constexpr int ret1 = dispaly(250);参数是常量,符合常量表达式函数的要求,此时constexpr是有效的
constexpr struct Person p2 = dispaly(p1); 参数是常量,符合常量表达式函数的要求,此时 constexpr 是有效的

  • 修饰构造函数

    如果想用直接得到一个常量对象,也可以使用constexpr 修饰一个构造函数,这样就可以得到一个常量构造函数了。常量构造函数有一个要求:构造函数的函数体必须为空,并且必须采用初始化列表的方式为各个成员赋值。

struct Person {
    constexpr Person(const char* p, int age) :name(p), age(age)
    {
        
    }
    const char* name;
    int age;
};

4. 自动类型推导

  • auto

    C++11auto 并不代表一种实际的数据类型,只是一个类型声明的 “占位符”,auto并不是万能的在任意场景下都能够推导出变量的实际类型,使用auto声明的变量必须要进行初始化,以让编译器推导出它的实际类型,在编译时将auto占位符替换为真正的类型。

//语法
auto 变量名 = 变量值;

auto x = 3.14; // x 为浮点值
auto y = 520; //y 为int
auto z = 'a'; // z 为char
auto nb; //error 必须初始化

? 不仅如此,auto 还可以和指针、引用结合起来使用也可以带上 const、volatile限定符,在不同的场景下有对应的推导规则,规则内容如下:

? 当变量不是指针或者引用类型时,推导的结果中不会保留const、volatile关键字
? 当变量是指针或者引用类型时,推导的结果中会保留const、volatile关键字

void autoTest()
{
	int temp = 100;

	auto* a = &temp; //a的类型为int* auto 为int
	auto b = &temp; //b的类型为int* auto 为 int*
	auto& c = temp; //c的类型为int& auto为 int
	auto d = temp; //d的类型为int auto为int

	const auto a1 = temp;  //变量a1的类型为const int,所以auto为int
	auto a2 = a1; //变量a2数据类型为int 因为a2没有声明为指针或引用因此const属性被去掉,auto为int
	const auto& a3 = temp; // 变量a3的类型为const int&,a3被声明为引用所以const属性保留,auto为int
	auto& a4 = a3; // 变量a4数据类型为const int&,a4被声明为引用因此 const 属性被保留,auto 为 const int 类型
}
  • decltype

    在某些情况下,不需要或者不能定义变量,但是希望得到某种类型,这时候就需要使用C++11提供的关键字decltype关键字了。它的作用是编译器编译的时候推导出一个表达式的类型

//语法
decltype(表达式)
    
int a = 10;
decltype(a) b = 99; // b int
decltype(a+3.14) c = 52.13 // C double

需要注意:表达式是一个左值,或者被括号 ( ) 包围,使用 decltype 推导出的是表达式类型的引用(如果有 const、volatile限定符不能忽略)

class Test{
public:
    int num;
};
int main(){
const Test obj;
//带有括号的表达式
decltype(obj.num) a = 0;	//int
decltype((obj.num)) b = a;	//括号 int&
//加法表达式
int n = 0, m = 0;
decltype(n + m) c = 0;	//int
decltype(n = n + m) d = n;	//左值 int&
}

decltype应用:

template<typename T>
class Container{
public:    
	void printContainer(T& c){
        for(_it=c.begin();_it!=c.end();_it++){
            cout<<*_it<<" ";
        }
        cout<<endl;
    }
private:
    decltype(T().begin()) _it;	//用来推到迭代器类型
};

int main(){
    const list<int> lst{1,2,3,4,5,6};
    Container<const list<int>> obj;
    obj.printContainer();
    return 0;
}
  • 返回类型后置

    在泛型编程中,可能需要通过参数的运算来得到返回值的类型:

#include <iostream>
using namespace std;
// R->返回值类型, T->参数1类型, U->参数2类型
template <typename R, typename T, typename U>
R add(T t, U u)
{
    return t + u;
}

int main()
{
    int x = 520;
    double y = 13.14;
    // auto z = add<decltype(x + y), int, double>(x, y);
    auto z = add<decltype(x + y)>(x, y);	// 简化之后的写法
    cout << "z: " << z << endl;
    return 0;
}

? 在C++11增加了返回类型后置语法,说白一点就是将decltypeauto结合起来完成返回类型的推导。

//语法格式
auto func(arg1,arg2,...) -> decltype(参数表达式)

通过上述返回类型后置代码的分析,可得到结论:auto会追踪decltype()推导出的类型,由此上边的add()函数可以做如下修改:

template <typename T, typename U>
auto add(T t, U u) -> decltype(t+u)
{
    return t + u;
}

5. finaloverride

  • final

? C++增加了final关键字来限制某个类不能被继承,或者某个虚函数不能被重写

  1. 修饰函数
class Base{
 public:  
    virtual void test(){}
};

class child:public Base{
 public:
    void test()final{}
};

class GrandChild:public child{
public:
    // 语法错误,不允许重写
    void test(){}
}
  1. 修饰类
class Base final
{
public:
    virtual void test(){}
};
// 语法错误
class Child : public Base
{};
  • override

    override 关键字确保在派生类中声明的重写函数与基类的虚函数有相同的签名,同时也明确表明将会重写基类的虚函数,这样就可以保证重写的虚函数的正确性,也提高了代码的可读性

class Base
{
public:
    virtual void test()
    {
        cout << "Base class...";
    }
};

class Child : public Base
{
public:
    void test() override
    {
        cout << "Child class...";
    }
};

6. 模板的优化

  • 模板的右尖括号

    在泛型编程中,模板实例化有一个非常繁琐的地方,那就是连续两个右尖括号>>会被编译器解析成右移操作符,而不是模板参数表的结束。

template<typename T>
class Base{
public:  
	void test(T& c){
		auto it	= c.begin();
        for(;it!=c.end();it++){
            cout<<*it<<" ";
        }
        cout<<endl;
    }    
};

int main()
{
    vector<int> v{1,2,3,4,5,6,7};
    Base<vector<int>> b;
    b.test();
    return 0;
}

如果使用 C++98/03标准来编译上边的这段代码,就会得到如下的错误提示:

test.cpp:25:20: error: '>>' should be '> >' within a nested template argument list
     Base<vector<int>> b;

根据错误提示中描述模板的两个右尖括之间需要添加空格,这样写起来就非常的麻烦,C++11改进了编译器的解析规则,尽可能地将多个右尖括号(>)解析成模板参数结束符,方便我们编写模板相关的代码。

  • 默认模板参数

C++98/03标准中,类模板可以有默认的模板参数:

template<typename T=int,typename T t = 520>
class Base{};

int main(){
    Test<> t; 
}

但是不支持函数的默认模板参数,在C++11中添加了对函数模板默认参数的支持:

template<typename T = int> //C++98/03不支持这种写法 C++11之后支持
void func(T t){
    cout<<t<<endl;
}

int main()
{
    func(100);
    return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-24 15:22:34  更:2021-08-24 15:23:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 6:05:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计