cpp_03_引用_类型转换_温和强转_面向对象

发布时间:2023年12月17日

1? 引用的应用

1.1? 数据传递--值传递

? ? ? ? C语言只要涉及数据传递(例如:初始化、赋值、传参、返回值),

? ? ? ? 都为值传递(将数据复制一份给到目标内存)。

// value.cpp 值传递:将数据复制一份给别人
#include <iostream>
using namespace std;

void foo( int x ) {  }

int bar( ) {
    int m = 8888;
    return m;
}

int main( void ) {
    int a = 10; // 初始化
    a = 20; // 赋值

    foo( a ); // 传参

    /*|8888|*/bar( ); // 返回值
    return 0;
}

? ? ? ? C++语言因为有引用,可以不做值传递。?

? ? ? ? 1)引用型形参:函数的形参是实参的别名,避免对象复制的开销。

? ? ? ? ? ? ? ? 非常引用型参数,可在函数中修改实参值;

? ? ? ? ? ? ? ? 引用型参数,防止了对实参的意外修改,? 也接受常量型实参(右值)。

// vparam.cpp 引用 作为函数的 形参
// 当我们在设计一个函数时,只要可以确定在函数内部绝对不修改实参,那么大胆的加上const
#include <iostream>
using namespace std;

void Swap( int* x, int* y ) { // 
    int z = *x;
    *x = *y;
    *y = z;
}

void Swap( int& x, int& y ) { // 非常引用型 形参:函数内部可以直接修改实参
    int z = x;
    x = y;
    y = z;
}
void Printer( const int& x, const int& y ) { // 常引用型 形参:能够防止意外修改实参
//  x = 888; // 编译器会提醒我们read-only  (打印机就应该原样打印哦)
    cout << x << ' ' << y << endl;
}

int main( void ) {
    int a=10, b=20;
    Swap( a, b );
//  Swap( &a, &b ); // 这种写法并不直观
    cout << "a=" << a << ", b=" << b << endl;

    Print( a, b );
    Print( 888, 999 ); //接受常亮型实参(右值)
    return 0;
}

? ? ? ? ?2)引用型的返回值:从函数中返回引用,一定要保证函数返回后,该引用的目标依然有效

? ? ? ? ? ? ? ? ????????-可以返回全局静态变量的引用

? ? ? ? ? ? ? ? ????????-可以返回在中动态创建(new)的对象的引用

? ? ? ? ? ? ? ? ????????-可以返回引用型参数本身

? ? ? ? ? ? ? ????????? -可以返回成员变量的引用?

? ? ? ? ? ? ????????? ? -可以返回调用对象自身的引用?

? ? ? ? ? ? ? ????????? -不能返回局部变量的引用

? ? ? ? ???????非常引用型返回值:通过引用可以修改目标

? ? ? ? ???????引用型返回值:通过引用不能修改目标

// vreturn.cpp 引用 作为函数的 返回值
#include <iostream>
using namespace std;
int g_value = 0;
int& foo() { // 非常引用型 返回值:可以通过引用修改目标
    return g_value;
}
const int& fooo() { // 常引用型 返回值:不可以通过引用修改目标
    return g_value;
}

int& bar() {
    static int s_value=0;//这行代码是在程序启动时就执行,而且只执行1次,不是每次调bar都执行
    cout << "s_value=" << s_value << endl;
    return s_value;
}

int& hum() {
    int* p = new int;
    return *p;
}

int& fun( int& x ) {
    // ...
    return x; // 返回 引用型 参数本身
}
/*
int& boo() {
    int m = 666;
    return m; // 不要返回局部变量的引用
}
*/
int main( void ) {
    foo() = 100;
    cout << "g_value=" << g_value << endl;

//    fooo() = 888; // readonly - error

    bar() = 200;
    bar();

    hum() = 300;

    int a_value = 0;
    fun(a_value) = 400;
    cout << "a_value=" << a_value << endl;

//  boo();
    return 0;
}

? ? ? ? 在实现(汇编)层面,引用就是指针,但在C++语言层面,引用不是实体类型,由此推导出,C++语言层面,引用与指针存在明显的差别:

? ? ? ? 1)指针可以不初始化,其目标可在初始化后随意变更(指针常量除外),

? ? ? ? ? ? ? 引用必须初始化,且一旦初始化就无法变更其目标。

? ? ? ? 2)存在空指针,不存在空引用

? ? ? ? 3)存在指向指针的指针,不存在引用的引用

? ? ? ? 4)存在指针的引用,不存在引用的指针

? ? ? ? 5)存在指针数组,不存在引用数组,但存在数组引用。

// poi_ref 指针 和 引用 的差别
#include <iostream>
using namespace std;

int main( void ) {
    int a=10, b=20;

    int* pa = &a; // 指针可以不做初始化,也可以做初始化
    pa = &b; // 指针可以随意变更它所指向的目标内存

    int& ra = a; // 引用必须初始化
    ra = b; // 引用不可以随意变更它所代表的目标内存( ra仍然是a的别名 )

    pa = NULL; // 存在空指针
//  ra = NULL; // 不存在空引用

    int** ppa = &pa; // 存在二级指针
//  int&& rra = ra;  // 不存在二级引用

    int* &rpa = pa; // 存在指针的引用  !!
//  int& *pra = &ra; // 不存在引用的指针
    int* p = &ra; // 这里取的并不是引用本身的地址,而是引用的目标内存a的地址

    int x, y, z;
    int*parr[3] = {&x, &y, &z}; // 存在指针的数组
//  int&rarr[3] = {x,y,z}; // 不存在引用的数组
    
    int arr[3];
    int(&rr)[3] = arr; // 存在数组的引用
    return 0;
}

?

2? 显示类型转换(强转)

? ? ? ? C风格的显示类型转换:????????(int)a?

? ? ? ? C++风格的显示类型转换:? ? int(a)?

// convert_pre.cpp 显式(强制)类型转换
#include <iostream>
using namespace std;

int main( void ) {
    int a;  double b;   float c;    short d;    char e;
    // 任何基本类型变量之间都可以 隐式转换
    a = b = c = d = e;
    e = d = c = b = a;
    // 任何其他类型的指针 到 void* 都可以隐式转换
    void* pv = &a;
    pv = &b;
    pv = &c;
    pv = &d;
    pv = &e;
    // void* 到 任何其他类型的指针 都必须强转(显式转换)
    int* pa = (int*)(pv);
    double* pb = (double*)(pv);
    float* pc = (float*)(pv);
    short* pd = (short*)(pv);
    char* pe = (char*)(pv);
    // 任何类型的 非常指针 到 同类型的常指针 都可以隐式转换
    const int* cpa = pa;
    const double* cpb = pb;
    const float* cpc = pc;
    const short* cpd = pd;
    const char* cpe = pe;
    // 任何类型的 常指针 到 同类型非常指针 都必须强转
    pa = (int*)(cpa);
    pb = (double*)(cpb);
    pc = (float*)(cpc);
    pd = (short*)(cpd);
    pe = (char*)(cpe);
    return 0;
}

3? 温和强转

3.1? 静态类型转换

????????????????static_cast<目标类型>(源类型变量)

????????????????隐式类型转换的逆转换(去常除外)

????????????????自定义类型转换?

3.2??动态类型转换?

????????????????dynamic_cast<目标类型>(源类型变量)?

????????????????多态父子类指针或引用之间的转换?

3.3? 常类型转换

????????????????const_cast<目标类型>(源类型变量)

????????????????去除指针或引用上的const属性

3.4? 重解释类型转换

????????????????reinterpret_cast<目标类型>(源类型变量)

????????????????任意类型的指针之间的转换

????????????????任意类型的引用之间的转换

????????????????任意类型的指针和整型之间的转换

// convert.cpp 显式(强制)类型转换
#include <iostream>
using namespace std;

int main( void ) {
    int a;  double b;   float c;    short d;    char e;
    // 任何基本类型变量之间都可以 隐式转换
    a = b = c = d = e;
    e = d = c = b = a;
    // 任何其他类型的指针 到 void* 都可以隐式转换
    void* pv = &a; // int*->void*
    pv = &b;
    pv = &c;
    pv = &d;
    pv = &e;
    // void* 到 任何其他类型的指针 都必须强转(显式转换)*************
    int* pa = static_cast<int*>(pv); // void*->int*的反向int*->void*可以隐式
    double* pb = static_cast<double*>(pv);
    float* pc = static_cast<float*>(pv);
    short* pd = static_cast<short*>(pv);
    char* pe = static_cast<char*>(pv);
    // 任何类型的 非常指针 到 同类型的常指针 都可以隐式转换
    const int* cpa = pa; // int*-->const int*
    const double* cpb = pb;
    const float* cpc = pc;
    const short* cpd = pd;
    const char* cpe = pe;
    // 任何类型的 常指针 到 同类型非常指针 都必须强转***************
    pa = const_cast<int*>(cpa); // 去常属性
    pb = const_cast<double*>(cpb);
    pc = const_cast<float*>(cpc);
    pd = const_cast<short*>(cpd);
    pe = const_cast<char*>(cpe);
    // 除了void*外,其他任何类型的指针之间都必须强转*************
    pa = reinterpret_cast<int*>(pb); // double*-->int*
    pb = reinterpret_cast<double*>(1000); // int-->double*
    return 0;
}

?

4? 面向对象

4.1? what

? ? ? ? 一切皆对象。

? ? ? ? 把大型软件看成是由多个对象组成的团推。

? ? ? ? 对象拥有足够的智能,能够理解来自其他对象的信息,并以适当的行为作出反应。

? ? ? ? 面向对象的三大特征:封装、继承、多态。

4.2? why

? ? ? ? 相比分而治之的结构化程序设计,强调大处着眼的面向对象程序设计思想,更适合开发大型软件。

? ? ? ? 得益于代码复用等面向对象的固有特征,软件开发的效率获得极大提升,成本却大幅降低。

4.3? how

? ? ? ? 至少掌握一种面向对象的程序设计语言,如C++

? ? ? ? 深入理解封装、继承、多态等面向对象的重要概念

? ? ? ? 学习设计模式,源自多年成功经验的积累总结。

第三个错误:等号右边是右值,故等号左边应为万能引用int* const &r?:

//test.cpp
#include <iostream>
using namespace std;


int main( void ) {
    int arr[9] = {9,3,1,4,2,7,5,8,6};

    int* p = arr;       // 正确  &arr[0]
    
    int(*pp)[9] = &arr; // 正确

//  int* &r = arr;      // 错误 &arr[0]     
    int* const& r = arr;// 正确

    int(&rr)[9] = arr;  // 正确
}

文章来源:https://blog.csdn.net/qq_33331020/article/details/135046207
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。