11.C++相较于 C 语言的增强

1.C++相较于 C 语言的增强

1.1引用 Reference

1.1.1 引用基础案例

&

定义了一个 int 类型的引用,引用名称为 ret ,使用 num 赋值当前引用,可以认为

​ 1.ret 是一个引用

​ 2.ret 是 num 变量的别名

#include <iostream>

using namespace std;

int main(int argc, char const *argv[])
{
    int num = 10;
    /*
    C++ 特定的数据形式【引用】需要使用的【标记】标点符号
        &
    定义了一个 int 类型的引用,引用名称为 ret ,使用 num 赋值当前引用

    可以认为
        1.ret 是一个引用
        2.ret 是 num 变量的别名
    */
    int &ret = num;

    cout << "num = " << num << endl;
    cout << "ret = " << ret << endl;
    cout << "-----------------------" << endl;
    num = 20;
    cout << "num = " << num << endl;
    cout << "ret = " << ret << endl;
    cout << "-----------------------" << endl;
    ret = 1000;
    cout << "num = " << num << endl;
    cout << "ret = " << ret << endl;
    return 0;
}

1.1.2一个变量可以有多个引用

一个变量可以同时有多个引用,就例如一个人可以有多个外号

定义了一个 int 类型的引用,引用名称为 ret ,使用 num 赋值当前引用。

ret1 ret2 ret3 都是 num 的引用。

#include <iostream>

using namespace std;

int main(int argc, char const *argv[])
{
    int num = 200;
    int & ref1 = num;
    int & ref2 = num;
    int & ref3 = num;

    cout << "num : " << num << endl;
    cout << "ref1 : " << ref1 << endl;
    cout << "ref2 : " << ref2 << endl;
    cout << "ref3 : " << ref3 << endl;

    cout << "-------------" << endl;

    ref3 = 1000;
    cout << "num : " << num << endl;
    cout << "ref1 : " << ref1 << endl;
    cout << "ref2 : " << ref2 << endl;
    cout << "ref3 : " << ref3 << endl;
    return 0;
}
1.1.3引用在函数参数中的使用

引用在函数参数中使用,相当于地址传递

优势

​ 1.相较于指针方式节省空间,引用不占用额外的内存空间,指针变量占内存的 8 个字节(64位操作系统)

​ 2.引用不会有额外的运算符使用,操作简单,使用方便

​ 3.引用效率高于指针。

#include <iostream>

using namespace std;

// 值传递
void swap1(int n1, int n2);

// 地址传递
void swap2(int *p1, int *p2);

/*
引用传递
当前函数所需的参数类型是引用类型

@param r1 int 类型引用
@param r2 int 类型引用
*/
void swap3(int &r1, int &r2);

int main(int argc, char const *argv[])
{
    int num1 = 200;
    int num2 = 1000;

    swap1(num1, num2);
    cout << "num1 = " << num1 << endl;
    cout << "num2 = " << num2 << endl;
    cout << "------------------" << endl;

    swap2(&num1, &num2);
    cout << "num1 = " << num1 << endl;
    cout << "num2 = " << num2 << endl;
    cout << "------------------" << endl;

    /*
    引用的优势
        1,相较于指针方式省空间,引用不占用额外的内存空间
        指针变量占用内存 8 个字节(64位系统)
        2,引用不会有额外运算符使用,操作简单,使用方便
        3,引用效率高于指针、
    swap3(num1,num2);
        参数赋值操作相当于
            int & r1 = num;
            int & r2 = num2;
    */
    swap3(num1, num2);
    cout << "num1 = " << num1 << endl;
    cout << "num2 = " << num2 << endl;
    cout << "------------------" << endl;
    return 0;
}
void swap1(int n1, int n2)
{
    int temp = n1;
    n1 = n2;
    n2 = temp;
}

void swap2(int *p1, int *p2)
{
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}

void swap3(int &r1, int &r2)
{
    int temp = r1;
    r1 = r2;
    r2 = temp;
}
1.1.4指针引用

可以降低代码的逻辑复杂度,提升代码效率,同时节约内存

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

struct  Student
{
    int id;
    char name[32];
    int age;
};
/*
当前函数所需参数为二级指针,需要修改外部指针变量存储的数据内容
如果提供的参数类型为一级指针,有且只能修改当前指针指向的数据空间
内容,无法修改当前变量存储数据情况,提供二级指针,可以修改当前指针
变量存储的数据内容
*/
void alloc_new_memory(Student ** stu);

/*
当前参数所需参数为【Student 类型指针引用】,可以直接传入 Student *
指针类型
降低代码的逻辑复杂度,提升代码效率,同时节约内存
*/
void alloc_new_memory_by_reference(Student *& stu);

int main(int argc, char const *argv[])
{
    Student *stu = (Student *)malloc(sizeof(Student));
    memset(stu,0,sizeof(Student));

    cout << "stu : " << stu << endl;

    alloc_new_memory(&stu);
    cout << "stu : " << stu << endl;

    alloc_new_memory_by_reference(stu);
    cout << "stu : " << stu << endl;

    free(stu);
    return 0;
}

void alloc_new_memory(Student **stu)
{
    free(*stu);
    int * arr = (int *)malloc(sizeof(int) * 10);
    *stu = (Student *)malloc(sizeof(Student));
    memset(*stu,0,sizeof(Student));
    free(arr);
}
void alloc_new_memory_by_reference(Student * & stu)
{
    free(stu);
    int * arr = (int *)malloc(sizeof(int) * 10);
    stu = (Student *)malloc(sizeof(Student));
    memset(stu,0,sizeof(Student));

    free(arr);
}

1.2const 关键字

1.1.1基本特征

基本变量 const 修饰

#include <iostream>

using namespace std;
int main(int argc, char const *argv[])
{
    const int num = 10;

    cout << "num : " << num << endl;
    
    num = 12;// 会报错
    /*
    error: assignment of read-only variable ‘num’
	const 修饰当前变量,可以简单认为当前变量为常量
	
	后续无法进行赋值操作
	当前 num 只读 【read-only】
    */
    return 0;
}

const int*p

const 修饰限制指针指向数据内容空间

p 存储的地址可以改变,p 指向地址的数据内容不可修改

#include <iostream>

using namespace std;
int main(int argc, char const *argv[])
{
    const int num = 10;

    cout << "num : " << num << endl;

    const int *p = &num;
    const int num1 = 100;

    /*
    *p = 200; ERROR 表达式必须是可修改的左值C/C++
    *p ==>  num 而 num 是 read-only 只读变量
    p  = &num; const int * p 指针指向的数据内容空间
    不可以修改,但是存储的地址可以修改。
    */
    p = &num1;
    return 0;
}

const int * const p

const 修饰限制指针指向数据内容空间,同时 const 修饰限制指针变量数据存储地址

#include <iostream>

using namespace std;
int main(int argc, char const *argv[])
{
    int num1 = 100;
    const int num = 10;
    const int * const p1 = &num;

    /*
    *p1 = 200;
    *p1 assignment of read-only location ‘*(const int*)p1’
    指向空间数据内容无法修改,是一个常量
    p1 = &num1;
    p1 error: assignment of read-only variable ‘p1’
    p1 也是一个常量,指针常量存储地址不可以修改
    */
    return 0;
}

int * const p

const 修饰限制指针变量数据存储

int num2 = 200;
int * const p2 = &num2;
int num3 = 100;
/*
p2 指向数据空间内容可以修改,但是存储的地址不能修改
*/
*p2 = 1000;// √
p2 = &num3; // ×
1.2.2 使用 const 替代 #default 无参数宏

宏只可以做简单的替换,不会考虑
1.数据类型问题
2.语法出错问题

const 修饰变量作为常量使用,具有的优点
1.具备数据类型特征,可以检查数据类型情况
2.有一定的语法限制,可以前置错误情况
3.使用全局变量形式完成 const 常量限制,功能性和宏类似,安全性更好

#include <iostream>
#define COUNT 10
const int num = 10;
using namespace std;

int main(int argc, char const *argv[])
{
    cout << "count : " << COUNT << endl;
    cout << "num : " << num << endl;
    return 0;
}

1.3 new 和 delete

1.3.1案例

C++ 用于动态分配内存的关键字,效果和 C 语言 malloc calloc realloc free 一致

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>

using namespace std;

int main(int argc, char const *argv[])
{
    /*
    C 语言申请内存方式和释放方式
    */
    int *arr = (int *)malloc(sizeof(int) * 10);
    memset(arr, 0, sizeof(int) * 10);

    free(arr);
    arr = NULL;

    /*
    C++ 申请内存方式和释放方式
    */
    int *arr2 = new int[10];
    memset(arr2, 0, sizeof(int) * 10);

    // 使用
    for (int i = 0; i < 10; i++)
    {
        arr2[i] = i * 2;
    }
    for (int i = 0; i < 10; i++)
    {
       cout << "arr2[" << i << "] = " << arr2[i] << endl;
    }

    delete arr2;
    arr2 = NULL;
    
    
    return 0;
}
1.3.2 结构体空间内容操作
#include <iostream>
using namespace std;
struct Student
{
    int id;
    string name;
    int age;
};
int main(int argc, char const *argv[])
{
    /*
    new 申请内存【堆区】空间,创建一个可以存储 Student 数据内存空间
    返回对应空间首地址
    */
    Student *stu = new Student;
    stu->id = 10;
    stu->name = "小绿茶z";
    stu->age = 18;

    cout << "ID : " << stu->id << endl;
    cout << "Name : " << stu->name << endl;
    cout << "Age = " << stu->age << endl;

    delete stu;
    stu = NULL;
    return 0;
}

1.4 内联函数

inline 关键字修饰

在C++中,inline关键字用于提示编译器将函数的代码内联展开,而不是通过函数调用的方式执行。对于inline函数,通常在头文件中提供函数的定义,而不是在源文件中。这让编译器能够在每个调用点直接插入函数的代码,从而提高执行效率。

虽然对于inline函数不要求显式的函数声明,但在一些情况下,如果你想在不同的源文件中使用inline函数,最好在这些源文件中都提供相同的函数声明,以确保一致性。

inline 函数可以提升一定的开发效率,在代码执行前 inline 函数会替代调用位置内容,替代之前会检查以下内容

1.函数名

2.参数数据类型

3.整个 inline 函数结果是一个整体

#include <iostream>
using namespace std;
/*
有参宏,可以完成一定的替换代码内容,但是有以下内容
1.没有严格的数据类型的限制,没有数据类型检查
2.替换结果会因为宏内容导致结果不一致,无法满足程序期望
*/
#define ADD(a,b) a + b

/*
首先这里是一个函数,并且时有参数有返回值函数
函数声明有一个关键字修饰 inline
*/

inline int add(int a,int b)
{
    return a + b;
}
int main(int argc, char const *argv[])
{
    int ret = 0;
    ret = ADD(10,20);
    cout << ret << endl;
    ret = add(10,20);
    cout << ret << endl;
    
    return 0;
}

1.5函数参数补充说明

1.5.1关于无参数函数

C 语言中,如果按照严格的代码规范,无参数函数,小括号需要使用 void 占位

void test(void);

C++语言中,不需要用 void 占位

void test();
1.5.2 函数的默认参数
#include <iostream>

using namespace std;

/*
声明位置有一个参数存在默认值
*/

void test(int num1,int num2 = 10);

int main(int argc, char const *argv[])
{
    // 如果函参数带有默认值,对应参数可以不提供实际参数
    test(100);

    // 默认值可以修改
    test(200,1000);

    return 0;
}

// 函数的实现位置,不需要再次明确函数参数默认值
void test(int num1,int num2)
{
    cout << "num1 : " << num1 << endl;
    cout << "num2 : " << num2 << endl;
}
1.5.3重载【重点!】

函数的重载

1.在同一个区域范围内,同一个命名空间,同一个文件,同一个类内,函数名称一致,但是函数的形式参数列表,数据类型,数据顺序,数据个数必须不一致。

2.函数的返回值不作为函数的唯一标记【会有语法错误,重复定义】

#include <iostream>
using namespace std;

/*
函数的返回值类型不作为函数的唯一标记,【语法错误】函数重复定义
无法通过函数名(实际参数数据类型)来明确目标函数是哪一个
int test(); 

【要求】
    1.在同一个区域范围内
    2,函数名必须要一致
    3,函数的形式参数列表必须不一致
*/
void test();
void test(int num);

int main(int argc, char const *argv[])
{
    test();
    test(10);

    return 0;
}

void test()
{
    cout << "无参数 test " << endl;
}
void test(int num)
{
    cout << "num : " << num << endl;
}

2.动态数组实现

2.1功能概述

整体结构为结构体,内存使用指定类型数组,针对于当前指定的类型,完成对应的【增删改查】

2.2设计整个结构体的基本情况

考虑到数组操作中,容量问题较为复杂,可以在结构体中设计对应的数据,将容量和有效元素个数进行保存

#define DEAFULT_CAPACITY 10
struct MyArray
{
    // 存储 Student * 指针数据数组,默认容量为 10
    Student *arr[DEAFULT_CAPACITY];
    // 整个底层数组的容量
    int capacity = DEAFULT_CAPACITY;
    // 当前数组中存储的有效元素个数
    int size;
};

2.3学生相关数据设计

Student.h 头文件

#ifndef _STUDENT_H_
#define _STUDENT_H_

#include <iostream>

using namespace std;
struct Student
{
    int id;
    string name;
    int age;
    
    void setId(int id);
    int getId();
    
    void setName(string name);
    string name();
    
    void setAge(int age);
    int getAge();
    
};

student.cpp C++ 文件

#include "student.h"
void Student::setId(int id) { this->id = id; }
int Student::getId() { return id; }

void Student::setName(string name) { this->name = name; }
string Student::getName() { return name; }

void Student::setAge(int age) { this->age = age; }
int Student::getAge() { return age; }

2.4 为什么用 this 指针

在C++中,this 指针是一个指向当前对象的指针,它在类的成员函数中起到指向当前对象的作用。当你使用成员函数去修改或访问成员变量时,你需要使用this指针。

使用this->是因为在成员函数内,this指针是一个指向当前对象的指针,而成员变量是属于对象的。因此,为了明确指出你想要访问的是对象的成员变量而不是局部变量,使用this->是一个显式的方式。

void Student::setId(int id) { this->id = id; }
int Student::getId() { return id; }

在这里,this->id表示当前对象的id成员变量,而id表示该成员函数的参数。使用this->可以帮助消除潜在的歧义,确保你正在访问对象的成员而不是同名的局部变量

总的来说,使用this->是一种良好的编程实践,特别是在成员函数内部,它提高了代码的清晰度和可读性。

用 this 指针的情况:

​ 1.区分局部变量和成员变量: 当成员函数的参数与成员变量同名时,使用this可以明确指出你正在访问对象的成员变量。

​ 2.在类的方法中返回当前对象: 在链式调用中,你可能希望在一个成员函数中返回当前对象,以便可以继续在同一个对象上调用其他函数。

MyClass& MyClass::increment() {
    this->x++;
    return *this; // 返回当前对象的引用
}

​ 3.在成员函数内部访问其他成员函数: 在一个成员函数内部,你可以使用this指针来调用其他成员函数。这是因为成员函数可以直接访问当前对象的成员。

void MyClass::doSomething() {
    this->increment(); // 调用当前对象的成员函数
}

​ 通常情况下,如果在成员函数中没有同名的局部变量,你可以选择性地省略this,因为编译器会自动理解你指的是当前对象。使用this通常是为了增加代码的清晰性和可读性。在一些简单的情况下,可以选择不使用this

  • 39
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值