C++11语言可用性的强化

2024-03-18 10:38
文章标签 语言 c++ 可用性 强化

本文主要是介绍C++11语言可用性的强化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

声明:内容来自实验楼《C++ 11/14 高速上手教程》,由本人整理、实验得来。

一、nullptr

nullptr 出现的目的是为了替代 NULL。在某种意义上来说,传统 C++ 会把 NULL0 视为同一种东西,这取决于编译器如何定义 NULL,有些编译器会将 NULL 定义为 ((void*)0),有些则会直接将其定义为 0
因此应该用nullptr来代替NULL

二、类型推导

C++11 引入了 autodecltype 这两个关键字实现了类型推导,让编译器来操心变量的类型。这使得 C++ 也具有了和其他现代编程语言一样,某种意义上提供了无需操心变量类型的使用习惯。

auto

auto i = 5; // i 被推导为 int
auto arr = new auto(10) // arr被推导为 int *

但是我认为像上面的应用最后自己定义类型,这样程序会比较清晰,那么在什么情况下时候使用auto,最适合的是在迭代器中使用。

#include<iostream>
#include<vector>
using namespace std;
int main() {auto a = 1;        //a为int类型cout << a << endl;  vector<int> v = { 1,2,3,4,5 };//auto it=v.begin()相当于vector<int>::iterator it=v.begin();for (auto it = v.begin(); it != v.end(); ++it)cout << *it << " " ;cout << endl;
}

**但是要注意的是:**auto 不能用于函数传参,因此下面的做法是无法通过编译的:

int add(auto x, auto y);会出现编译错误

#include <iostream>
int main() {auto i = 5;     //i为intint arr[10] = { 0 };auto auto_arr = arr; //auto_arr为int* 类型auto auto_arr2[10] = arr;  //编译错误return 0;
}

总结:在实际的编程中一般我只会将auto用在迭代器的类型推导中。

decltype

decltype 关键字是为了解决 auto 关键字只能对变量进行类型推导的缺陷而出现的。它的用法和 sizeof 很相似:
decltype(expression)

示例:

auto x = 1, y = 2;
decltype(x + y) z;   //z的类型为int,他是x+y的返回值决定的。

三、尾返回类型

有时,我们会遇到不知道该让函数返回何种类型,如
add(T x,U y)那么是个函数的返回类型是不固定的,但是我们不能写成
decltype(x+y) add(T x, U y);事实上这样的写法并不能通过编译。这是因为在编译器读到 decltype(x+y) 时,x 和 y 尚未被定义,因此C++11 还引入了一个叫做尾返回类型(trailing return type),利用 auto 关键字将返回类型后置。
如下所示:

#include <iostream>
using namespace std;
template<typename T, typename U>
auto add(T x, U y) ->decltype(x+y) {   //注意声明格式return x + y;
}
int main() {cout << add(3,3.5)<< endl;return 0;
}

但是c++14又有了新的突破,直接用auto add(T x,U y)即可,上述实验在vs2015都成功了。

四、区间迭代

C++11 引入了基于范围的迭代写法,这种写法更加的简单明了,很具有实用性。

#include <iostream>
#include<vector>
using namespace std;
int main() {vector<int> v = { 1,2,3,4,5 };for (auto it = v.begin(); it != v.end(); ++it)  //迭代器遍历cout << *it << " ";cout << endl;//如果要修改值,改为引用for (auto &c : v)  for (auto c : v)       //极大减少代码量cout << c << " ";return 0;
}

五、初始化列表

初始化是一个非常重要的语言特性,最常见的就是对对象进行初始化。在传统 C++ 中,不同的对象有着不同的初始化方法,例如普通数组、POD (plain old data,没有构造、析构和虚函数的类或结构体)类型都可以使用 {} 进行初始化,也就是我们所说的初始化列表。而对于类对象的初始化,要么需要通过拷贝构造、要么就需要使用() 进行。这些不同方法都针对各自对象,不能通用。

vector<int> v = { 1,2,3,4,5 };//采用初始化列表进行初始化
class Foo {
private:int value;
public:Foo(int) {}
};
Foo foo(1);             // 普通构造初始化

类中的构造函数中使用成员函数初始化:

#include <iostream>
#include<vector>
using namespace std;
class Base {
public:Base(int a, int b) : x(a), y(b) {};     ///承运列表初始化int x;int y;
};
int main() {Base base(1, 2);cout << base.x << " " << base.y << endl;return 0;
}

六、面向对象增强

委托构造

C++11 引入了委托构造的概念,这使得构造函数可以在同一个类中一个构造函数调用另一个构造函数,从而达到简化代码的目的:

#include <iostream>
#include<vector>
using namespace std;
class Base {
public:int value1;int value2;Base() {value1 = 1;}Base(int value) : Base() {  // 委托 Base() 构造函数value2 = 2;}
};int main() {Base b(2);std::cout << b.value1 << std::endl;std::cout << b.value2 << std::endl;
}

继承构造

在传统 C++ 中,构造函数是得不到继承的。如果一个子类代码没有编写对应的构造函数,那么将不能够直接使用父类的构造函数, C++11 引入了继承构造函数的概念:

#include <iostream>
#include<vector>
class Base {
public:int value1;int value2;Base() {value1 = 1;}Base(int value) : Base() {          // 委托 Base() 构造函数value2 = 2;}
};
class Subclass : public Base {
public:int value3;Subclass(int value3, int value2) : Base(value2) {   // 继承父类构造this->value3 = value3;}
};
int main() {Subclass s(3, 2);std::cout << s.value1 << std::endl;std::cout << s.value2 << std::endl;std::cout << s.value3 << std::endl;
}

显式虚函数重载

有时我们会遇到意外重载虚函数的问题,例如:

struct Base {virtual void foo();
};
struct SubClass: Base {void foo();
};

SubClass::foo 可能并不是程序员尝试重载虚函数,只是恰好加入了一个具有相同名字的函数。另一个可能的情形是,当基类的虚函数被删除后,子类拥有旧的函数就不再重载该虚拟函数并摇身一变成为了一个普通的类方法,这将造成灾难性的后果。C++11 引入了 overridefinal这两个关键字来防止上述情形的发生。

override

以前总以为overide是重写的意思,现在发现了自己的错误(too simple)。这里要特别注意重写和重载的区别。当重载虚函数时(这里指的是重载基类的虚函数,引入 override 关键字将显式的告知编译器进行重载,编译器将检查基函数是否存在这样的虚函数,否则将无法通过编译:

struct Base {virtual void foo(int);
};
struct SubClass : Base {//在vs中显示的是重载virtual void foo(int) override; // 合法virtual void foo(float) override; // 非法, 父类没有此虚函数
};
final

final 则是为了防止类被继续继承以及终止虚函数继续重载引入的。

struct Base {virtual void foo() final;
};
struct SubClass1 final : Base {
};                  // 合法struct SubClass2 : SubClass1 {
};                  // 非法, SubClass 已 finalstruct SubClass3 : Base {void foo(); // 非法, foo 已 final
};

这篇关于C++11语言可用性的强化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/822084

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现