【C++】c++11新特性(一)

这篇具有很好参考价值的文章主要介绍了【C++】c++11新特性(一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

{ }列表初始化

内置类型---对单值变量及数组的初始化

列表初始化时进行的类型转换

自定义类型---对类对象或结构的初始化

initializer_list

1. 定义接受 initializer_list 参数的构造函数

2. 在函数中使用 initializer_list 参数

3. 使用 initializer_list 与 vector 等容器

用于推断类型的关键字

auto  和  decltype

用于管理虚方法的说明符

final  和  override

final

1. 修饰类

2. 修饰虚函数

3. 修饰非虚成员函数

override


                                            


{ }列表初始化

内置类型---对单值变量及数组的初始化

下面是将花括号列表初始化用于单值变量的情形 . 如下代码:

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

可以看出 变量 num1 和 变量num2 都被初始化为6 ;因此,采用大括号这种初始化方式可使用等号(=),也可以省略不写

那如果花括号里我们什么都不写呢?那么它的值会是什么如下代码:

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

如上可看到花括号中如果什么都不写,这种情况下变量将被初始化为 0

将花括号列表初始化用于数组初始化的情形 ,数组在之前就可使用列表初始化,但c++11对列表初始化新增了一些功能。

      1. 初始化数组时可以省略等号(=);

      2. 在花括号内可以不包含任何东西,此时,所有元素都被初始化为0,这与单值变量初始化类似

如下代码:

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

此外,对列表初始化语法用于 new表达式中:

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

前两行只是申请了内存空间(即对于单个对象申请了一个int型大小的空间,对于多个对象申请了连续的4个大小的int型空间);后两行既申请了空间又对其进行了初始化。

列表初始化时进行的类型转换

c++11这种列表初始化常用于复杂的数据类型提供值列表,相较于c(内置类型)的初始化方式来说,c++11列表初始化对类型转换的要求更加严格。具体来说就是不允许把更宽的类型转换为窄的类型,比如:int-->char 不允许(当int的范围超出char时)。如下代码演示:

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

       通过上面的代码可以看到,162行是 c 风格的初始化,把一个int类型的值为3556(已超出char的范围)赋给char类型变量,编译器只给了警告:发生截断,但还是可以通过的;而使用c++11的大括号{}列表初始化编译器就会直接报错,是不能通过编译的。因此,使用列表初始化时要注意类型间的转换

说明:列表初始化是禁止大类型向小类型转换的,上面是单值对象,数组也是一样的

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

自定义类型---对类对象或结构的初始化

将花括号列表初始化用于类对象,但要提供与某个构造函数的参数列表匹配的内容,并用大括号括起来。

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

花括号列表初始化可以用于类对象(要隐式类型转换,调用构造函数),是该类要支持单参数或多参数的构造函数(可以是带缺省值的) ;

说明:当用于new表达式 (想要申请并初始化多个对象) 时,如果申请的 对象个数 与 大括号中 初始化的个数不符(小于),这时,剩余的个数会去调用默认的构造函数初始化,此时需要有默认构造函数才行,否则会有编译错误:如:上面代码中 289 行,就需要提供默认构造函数才行,要么就对象个数与大括号中初始化数一致。

将花括号列表初始化用于结构体的情形

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

initializer_list

initializer_list 是一个模板类,它允许使用花括号初始化器({})来初始化对象。initializer_list 通常用于构造函数和函数参数以接受任意数量的元素进行初始化

这提供了一种方便的方式来初始化容器、数组或其他集合类型。

下面是initializer_list 的用法

1. 定义接受 initializer_list 参数的构造函数

#include <iostream>
#include <vector>
#include <initializer_list>
using namespace std;

class MyClass 
{
public:
    MyClass(initializer_list<int> il) 
    {
        for (auto& e : il) 
        {
            data.push_back(e);
        }
    }

    void print()  
    {
        for (auto& e : v) 
        {
            cout << e << " ";
        }
        cout << endl;
    }

private:
    vector<int> v;
};

int main() 
{
    MyClass mc = { 1, 2, 3, 4, 5 }; // 使用花括号初始化  
    mc.print(); // 输出: 1 2 3 4 5  

    return 0;
}

2. 在函数中使用 initializer_list 参数

#include <iostream>
#include <initializer_list>
using namespace std;

void print_list(initializer_list<int> il) 
{
    for (auto& e : il) 
    {
        cout << e << " ";
    }
    cout << endl;
}

int main() 
{
    print_list({ 10, 20, 30, 40, 50 }); // 输出: 10 20 30 40 50  

    return 0;
}

  3. 使用 initializer_list 与 vector 等容器

vector和其他STL容器通常都有接受initializer_list参数的构造函数,因此,可以直接使用花括号初始化:

int main() 
{
    vector<int> v = { 1, 2, 3, 4, 5 };

    for (auto& e: v) 
    {
        cout << e << " ";
    }

    cout << endl; // 输出: 1 2 3 4 5  

    return 0;
}

说明:

        1.  initializer_list对象只用于初始化,它们不是真正的容器,不支持修改操作(如push_back

        2. 如果类有多个构造函数,并且其中一些接受单个参数,可能会遇到与隐式类型转换相关的歧义。此时,可能需要使用explicit关键字来防止不期望的隐式转换

initializer_list提供了一种方便且灵活的方式来初始化对象和集合,使得代码更加清晰和易读

用于推断类型的关键字

auto  和  decltype

关键字auto之前是一个存储类型的说明符,但c++11重新定义了auto的含义:将 其用于实现自动类型推断。要求必须进行显示初始化,让编译器将定义对象的类型设置为初 始化值的类型

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

关键字decltype, 把变量的类型声明为表达式指定的类型。

1. 若decltype 指定的表达式没有括号,则所声明变量的类型和指定表达式的类型相同

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

代码中所声明的变量的类型 z、u、w 与 decltype括号中所指定的类型一样

注意:虽然 m和n 都是引用,但表达式 m+n 不是引用,因此,mn 的类型是 int 而不是 int&

是两个int的和;

2. 若decltype 指定的表达式是函数调用,则所声明变量的类型函数返回值的类型相同

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

注意:编译器是通过查看函数的原型 确定返回类型,而不会实际调用函数

3. 若decltype 指定的表达式是一个左值且带有括号,则所声明变量的类型左值的引用

【C++】c++11新特性(一),《C++面向对象》,c++,开发语言

上面代码中,q 是被括号括起来的,则声明的变量 v 的类型是 左值 q 的引用,注意与无括号的对比;

注意:若用decltype 声明的变量 是上面代码中 323 行 的形式 就必须要引用一个左值,否则编译会报错;如:decltype((q))   v;  //erro

说明:括号并不会改变表达式的值 和 左值性

用于管理虚方法的说明符

final  和  override

final

final 可用于修饰类、虚函数final 关键字主要用于那些设计为不应该被继承或不应该被重写的类和方法。使用final 可以增强代码的可读性和可维护性,因为它明确指出了哪些类和方法是封闭的,不应该被修改或扩展。同时,它也有助于防止由于错误地继承或重写而引起的潜在问题

下面是final的几种用法

1. 修饰类

final用于类时,表示这个类不能被继承。这有助于防止不希望被继承的类被意外地继承

class Base final 
{
    // ... 类成员 ...  
};

// 下面的代码会编译错误,因为Base类被声明为final  
class Derived : public Base 
{
    // ... 类成员 ...  
};
2. 修饰虚函数

当 final 用于虚函数时,表示这个虚函数在派生类中不能被重写。这有助于确保某些关键的函数行为在类的继承体系中保持不变

class Base {
public:
    virtual void func() final 
    {
        // ... 函数的实现  
    }
    // ... 其他成员 ...  
};

class Derived : public Base {
public:
    // 下面的代码会编译错误,由于 func()函数在Base类中被声明为final  
    void func()  // ... 想要重写的函数实现 ... 
    {
        // ... 函数的实现
    }
};
3. 修饰非虚成员函数

虽然非虚成员函数也可以使用final关键字,但这通常没有太多实际意义,因为非虚成员函数本来就不能被重写。

override

  override关键字用于显式地指示一个成员函数在派生类中重写了基类中的虚函数。使用override的好处在于,它提供了编译时的检查,确保你确实重写了基类中的某个虚函数。如果基类中没有相应的虚函数,编译器会报错,从而防止潜在的错误。

下面是override的用法:   

class Base {
public:
    virtual void func1() 
    {
        // 基类虚函数的实现  
    }

    // 非虚函数,不能被重写  
    void func2()
    {
        // ...  
    }
};

class Derived : public Base {
public:
    // 使用override关键字显式地表示我们重写了Base类的func1函数,
    // 也可以不使用override,但使用override可以提供额外的检查  
    void func1() override
    {
        // 派生类重写func1函数的实现  
    }

    // 尝试重写Base类的func2函数,但由于func2不是虚函数,这里会编译错误  
    // 即使使用了override关键字,也无法将其变为虚函数  
    void func2() override
    {
        // 尝试重写的实现,但会导致编译错误  
    }
};

在上面的演示中,Derived类继承了Base类,并重写了func1这个虚函数。通过在派生类的成员函数声明后添加override关键字,告诉编译器这个函数是重写的,并且编译器会检查基类中是否存在相应的虚函数。如果基类中没有相应的虚函数,编译器将报错。

注意:

       即使不使用override关键字,只要函数签名(包括返回类型和参数列表)与基类中的虚函数匹配,派生类中的成员函数也会被视为重写了基类的虚函数。但是,使用override提供了额外的安全性,因为它强制要求基类中存在一个可重写的虚函数。

只有虚函数才能被重写。如果尝试重写非虚函数,即使使用了override关键字,也会导致编译错误


      文章来源地址https://www.toymoban.com/news/detail-861760.html

到了这里,关于【C++】c++11新特性(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【跟小嘉学 Rust 编程】十七、面向对象语言特性

    【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学 Rust 编程】六、枚举

    2024年02月10日
    浏览(90)
  • 【Go语言快速上手(四)】面向对象的三大特性引入

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:Go语言专栏⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习更多Go语言知识   🔝🔝 GO语言也支持面向对象编程,但是和传统的面向对象语言(如CPP)有明显的区别,GO并不是纯粹的面对对象编程语言.所以说GO是支持面向对

    2024年04月26日
    浏览(54)
  • Rust编程语言入门之Rust的面向对象编程特性

    Rust 受到多种编程范式的影响,包括面向对象 面向对象通常包含以下特性:命名对象、封装、继承 “设计模式四人帮”在《设计模型》中给面向对象的定义: 面向对象的程序由对象组成 对象包装了数据和操作这些数据的过程,这些过程通常被称作方法或操作 基于此定义:

    2023年04月21日
    浏览(55)
  • 【c++随笔11】面向对象和封装

    原创作者:郑同学的笔记 原创地址:https://zhengjunxue.blog.csdn.net/article/details/131794661 qq技术交流群:921273910 C++ 是基于面向对象的程序,面向对象有三大特性 —— 封装、继承、多态。 当谈到C++编程时,面向对象编程(OOP:Object-Oriented Programming)和封装是两个重要的概念。通过

    2024年02月05日
    浏览(49)
  • 【C/C++】C语言和C++的区别 | 面向过程与面向对象

    创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡𖥦)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 🔥c++系列专栏:C/C++零基础到精通 🔥 给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ c语言内容💖:

    2024年02月07日
    浏览(44)
  • 【C++庖丁解牛】面向对象的三大特性之一多态 | 抽象类 | 多态的原理 | 单继承和多继承关系中的虚函数表

    🍁你好,我是 RO-BERRY 📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 需要声明的,本节课件中的代码及解释都是在vs2013下的x86程序中,涉及的指针都是4bytes。如果要其他平台

    2024年04月10日
    浏览(59)
  • c、c++、java、python、js对比【面向对象、过程;解释、编译语言;封装、继承、多态】

    目录 内存管理、适用 区别 C 手动内存管理:C语言没有内置的安全检查机制,容易出现内存泄漏、缓冲区溢出等安全问题。 适用于系统级编程 C++ 手动内存管理:C++需要程序员手动管理内存,包括分配和释放内存,这可能导致内存泄漏和指针错误。 适用于游戏引擎和系统级编

    2024年02月08日
    浏览(76)
  • 15面向对象特性

    在程序设计中,封装(Encapsulation)是对具体对象的一种抽象,即将某些部分隐藏起来,在程序外部看不到,其含义是其他程序无法调用。要了解封装,离不开“私有化”,就是将类或者是函数中的某些属性限制在某个区域之内,外部无法调用。 封装的作用: 1、保护隐私(把

    2023年04月23日
    浏览(39)
  • 【IMX6ULL驱动开发学习】11.驱动设计之面向对象_分层思想(学习设备树过渡部分)

    一个 可移植性好 的驱动程序,应该有三个部分组成 1、驱动框架程序(xxx_drv.c) — 对接应用层的 open read write 函数,不做GPIO具体操作 2、硬件操作程序(xxx_chip_gpio.c)— 执行具体的GPIO操作,初始化、读写 3、硬件资源定义程序(xxx_board.c,这在之后就过渡成了设备树)— 为

    2024年02月11日
    浏览(46)
  • 面向对象三大特性之一——継承(上篇)

    目录 前文 一.什么是継承? 1.1 継承的定义 1.2 継承的格式 1.2.1 継承的使用格式 1.2.2 継承关系和访问限定符 二,基类和派生类对象复制转换 三,継承中的作用域 四,派生类/子类中的默认成员函数 六,継承与友元  六,継承与静态成员 总结 本篇文章主要是详解面向对象三大

    2024年02月03日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包