【C++】C++补充知识&C++11及其特性

简介: 【C++】C++补充知识&C++11及其特性

@TOC

C++补充知识&C++11及其特性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9zkHAJv5-1633057703080)(补充C++11.assets/image-20210930092847356.png)]

explicit关键字

加在类构造函数前表明该构造函数是显式的,并非隐式的,不能进行隐式类型转换!

类构造函数默认情况下声明为隐式。

给构造函数加上关键字explicit使得该类创建对象必须显式调用构造。

student xiaohua(18);//显式构造
student xiaoming = 18;//隐式构造
student xiaoli("小李",18);//显式构造
student xiaomei = ("小美",18);//隐式构造-C++11之前编译不能过
//初始化参数列表C++11新增

看到=要想是赋值呢,还是隐式构造呢。

左值和右值的概念

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oPLFGMka-1633057703084)(01补充C++11.assets/image-20210930122633001.png)]

按字面意思,通俗的说,以赋值运算符=为界,左边的就是左值,右边的就是右值。

左值(lvalue)——代表一个在内存中占有确定位置的对象(就是有一个地址)。

右值(rvalue)——通过排他性来定义,每个表达式不是左值就是右值,rvalue是不在内存中占有确定位置的表达式,而是在存在寄存器中。

所有的左值(无论是数组,函数或不完全类型)都可以转化成右值。

函数返回值当引用

C++使用引用时的难点

  1. 当函数返回值为引用时

    若返回栈变量,不能称为其他引用的初始值,不能作为左值使用。

    (函数在栈上开辟空间存放形参和局部变量,这个变量所在内存空格占的位置不是固定的,再有一个函数压进栈来,原来的局部变量所在内存被覆盖。(变量和其对应的地址对不上了,该变量指向的那个地址所存的内容被覆盖了)-个人理解)

  2. 若返回静态变量或全局变量

    可以成为其他引用的初始值。

    即可作为右值使用,也可以作为左值使用。

  3. 返回形参当引用

    (注:C++链式编程中,经常用到引用, 例如运输符重载)

Array容器

详见-C++SLT容器中。

(取容器中元素的地址貌似是没有意义的,除非他里面的内容不在改变,因为有的容器中元素发生变化后,里面的容器元素是会发生移动的。)

其中,有意思的是empty()接口永远false,因为在构造的时候要指定数量。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VeY1Qdti-1633057703085)(01补充C++11.assets/image-20210930180201082.png)]

C++类型转换

C语言风格

double PI = 3.1415926;

int i = PI;//隐式类型转换

int i1 = (int)PI;//显式类型转换
int* addr = (int*)0x888888;//强制类型转换,整数直接指针

C++类型转换操作符

static_cast

静态类型转换,同时做检查给予提示。

int i = static_cast<int>(PI);
 
//父子类之间的类型转换
Dog* dog = new Dog;
//子类指针转型到父类指针
Animal* animal = static_cast<Animal*>(dog);
//父类指针转型到子类指针
Dog* dog2 = static_cast<Dog*>(animal);
Dog dog2;
//子类引用转型到父类引用
Animal& animal2 = static_cast<Animal&>(dog2);

//基本类型转换
int kk = 234;
char cc = static_cast<char>(kk);//都是模板

//把空指针转换成目标类型的空指针
int* p = static_cast<int*>(NULL);
Dog* dp = static_cast<Dog*>(NULL);

//把任何类型的表达式转化成void类型
int* p = new int[10];
void* vp = static_cast<void*>(p);
vp = p;//效果相同 

主要用法:

  • 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。上行指针或引用(派生类到基类)转换安全,下行不安全
  • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
  • 把空指针转换成目标类型的空指针。
  • 把任何类型的表达式转换成void类型。

(写了会提醒编译器检查,提醒其他程序员要注意。)

(没事别转。)

reinterpret_cast

(可以用于强制类型转换)

重新解释类型不同类型间的互转,数值与指针间的互转。

用法: TYPE b = reinterpret_cast < TYPE> (a)

TYPE必须是一个指针、引用、算术类型、函数指针.

int* p = reinterpret_cast<int*>(0x999999);//整型转指针
int* val = reinterpret_cast<int>(p);//指针转整型

Dog  dog1;
Animal* a1 = &dog1;

Animal& a2 = dog1;
Dog& dog3 = reinterpret_cast<Dog&>(a2);//引用强转用法

注意:滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。(低级别:在内存没啥差别)

与static_cast相加可替换掉C风格的类型转换。

dynamic_cast

动态类型转换

将一个基类对象指针cast到继承类指针,dynamic_cast 会根据基类指针是否真正指向继承类指针来做相应处理。失败返回null,成功返回正常cast后的对象指针。

( 看该父类是否真正指向该子类(因为有多个子类。))

(子类 xx = dynamic_cast<子类>(父类xx);

将一个基类对象引用cast 继承类对象,dynamic_cast 会根据基类对象是否真正属于继承类来做相应处理。失败抛出异常bad_cast。

void animalPlay(Animal* animal) {
    animal->cry();

    Dog* pDog = dynamic_cast<Dog*>(animal);
    if (pDog) {
        pDog->play();
    }
    else {//pDog == NULL
        cout << "不是狗,别骗我!" << endl;
    }

    Cat* pCat = dynamic_cast<Cat*>(animal);
    if (pCat) {
        pCat->play();
    }
    else {//pDog == NULL
        cout << "不是猫,别骗我!" << endl;
    }
}
void animalPlay(Animal& animal) {
    animal.cry();

    try {
        Dog& pDog = dynamic_cast<Dog&>(animal);
        pDog.play();
    }
    catch (std::bad_cast bc) {
        cout << "不是狗,那应该是猫" << endl;
    }

    try {
        Cat& pCat = dynamic_cast<Cat&>(animal);
        pCat.play();
    }
    catch (std::bad_cast bc) {
        cout << "不是猫,那应该是上面的狗" << endl;
    }

注意: dynamic_cast在将父类cast到子类时,父类必须要有虚函数一起玩。

const_cast

去掉const属性,仅针对于指针和引用。

void demo(const char p)
{
    //对指针去掉const 重新赋值
    char* p1 = const_cast<char*>(p);

    //直接去掉const修改
    const_cast<char*>(P)[0] = 'a';
}

常量字符串不行,考虑内存范围。

在去掉常量限定符之前,保证指针所指向的内存可被修改,不能修改则会引起异常。

类型转换使用建议

  1. static_cast静态类型转换,编译的时c++编译器会做编译时的类型检查;隐式转换;基本类型转换,父子类之间合理转换
  2. 若不同类型之间,进行强制类型转换,用reinterpret_cast<>() 进行重新解释。

    建议:

C语言中 能隐式类型转换的,在c++中可用 static_cast<>()进行类型转换。因C++编译器在编译检查一般都能通过;C语言中不能隐式类型转换的,在c++中可以用 reinterpret_cast<>() 进行强制类型解释**。

总结:static_cast<>()和reinterpret_cast<>() 基本上把C语言中的 强制类型转换给覆盖,注意reinterpret_cast<>()很难保证移植性。

3.dynamic_cast<>(),动态类型转换,安全的虚基类和子类之间转换;运行时类型检查

4.const_cast<>(),去除变量的只读属性


程序员必须清楚的知道: 要转的变量,类型转换前是什么类型,类型转换后是什么类型,转换后有什么后果。

一般情况下,不建议进行类型转换;避免进行类型转换。


相关文章
|
1月前
|
设计模式 安全 算法
【C++ 基础】超越边界:C++中真正不受访问修饰符限制的特性
【C++ 基础】超越边界:C++中真正不受访问修饰符限制的特性
36 0
|
1月前
|
设计模式 存储 缓存
【C++ 基本概念】深入探索C++ RTTI 特性
【C++ 基本概念】深入探索C++ RTTI 特性
61 0
|
1月前
|
自然语言处理 编译器 C语言
【C++ 20 新特性】参数包初始化捕获的魅力 (“pack init-capture“ in C++20: A Deep Dive)
【C++ 20 新特性】参数包初始化捕获的魅力 (“pack init-capture“ in C++20: A Deep Dive)
40 0
|
1月前
|
Linux C++ iOS开发
【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南(二)
【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南
253 2
|
1月前
|
Linux API C++
【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南(一)
【C++ 17 新特性 文件管理】探索C++ Filesystem库:文件和目录操作的全面指南
320 2
|
27天前
|
存储 安全 编译器
【C++】类的六大默认成员函数及其特性(万字详解)
【C++】类的六大默认成员函数及其特性(万字详解)
35 3
|
30天前
|
算法 安全 编译器
【C++ 17 新特性 折叠表达式 fold expressions】理解学习 C++ 17 折叠表达式 的用法
【C++ 17 新特性 折叠表达式 fold expressions】理解学习 C++ 17 折叠表达式 的用法
23 1
|
1月前
|
安全 算法 程序员
【C++ 空指针的判断】深入理解 C++11 中的 nullptr 和 nullptr_t
【C++ 空指针的判断】深入理解 C++11 中的 nullptr 和 nullptr_t
48 0
|
1月前
|
安全 编译器 程序员
【C++ 11 模板和泛型编程的应用以及限制】C++11 模板与泛型深度解析:从基础到未来展望
【C++ 11 模板和泛型编程的应用以及限制】C++11 模板与泛型深度解析:从基础到未来展望
78 0
|
1月前
|
算法 安全 程序员
【C++14 新特性 透明操作符】透视C++14透明操作符Functors:深入理解与实践
【C++14 新特性 透明操作符】透视C++14透明操作符Functors:深入理解与实践
41 3