#C++ 笔记一

news2024/9/19 10:39:15

重点:面试考试大概率会涉及,需要不借助任何资料掌握。
掌握:面试考试可能涉及,需要不借助任何资料掌握
熟悉:面试考试可能涉及,可以稍微参考资料掌握
了解:面试考试小概率涉及,能吹吹就行。

一、C++简介

1. 为什么要学习C++?

       C++是一个新的就业方向

2. C++可以做什么?

  • 嵌入式系统级开发。
  • 服务器开发、包括游戏服务器、推荐服务器、运营系统(数据处理、系统安全)
  • 人工智能
  • QT代码实现

拓展知识面 :C语言属于面向过程编程,C++是属于面向对象编程。

3. C++语言的发展史(了解)

1983年,贝尔实验室(Bell Labs)的Bjarne Stroustrup发明了C++。 C++在C语言的基础上进行了扩充和完善,是一种面向对象程序设计(OOP)语言。

Stroustrup说:“这个名字象征着源自于C语言变化的自然演进”。还处于发展完善阶段时被称为“new C”,之后被称为“C with Class”。C++被视为C语言的上层结构,1983年Rick Mascitti建议使用C++这个名字,就是源于C语言中的“++”操作符(变量自增)。而且在共同的命名约定中,使用“+”以表示增强的程序。

常用于系统开发,引擎开发、嵌入式开发等应用领域, 至今仍然是最受广大程序员喜爱的编程语言之一。

4. C++特点(了解)

  • 在支持C语言的基础上,全面支持面向对象编程。
  • 编程领域广泛,功能强大(最难学习的编程语言之一)。
  • C++语言的标准一直保持更新,本次课程主要以C++ISO98 和ISO11标准为主。
  • 为数不多支持底层操作的面向对象编程语言。
  • 在面向对象的编程语言中执行效率极高。

5. 面向对象编程

  • 对象
  • 封装
  • 继承
  • 多态

封装→继承→多态,被称为面向对象编程的三大特性

6. 面向过程与对象的区别(熟悉)

【思考】如果把大象装进冰箱,需要几步完成?

  1. (我)打开冰箱
  2. (我)把大象放进去
  3. (我)关上冰箱

上面的这种方式就是典型的面向过程的编程思想,这种思想关注的重点是“过程”,“过程”指的是一系列有序的步骤,只需要按照这个步骤来做,就可以得到预计的结果。这种思维方式偏向于计算机执行命令的本质,这种程序的特点就是执行效率高。(因为都是亲历亲为)。适合小体量的软件工程项目开发,偏向性能的项目一般这样做。

使用面向对象的思想把大象装进行冰箱:

  1. (我)把大象和冰箱拟人化
  2. (我)给大象和冰箱安排任务
  3. 大象和冰箱执行任务

面向对象的语言,关注的重点是“对象”。在计算机中“对象”可以理解为一系列由于某种联系而聚焦在一起的数据,在编程的过程中处理对象之间的关系,这种思想更接近于人类的思考方式。这种程序的执行效率低,但是编程效率高。适合大规模的软件项目。

面向过程,是以“怎么解决问题”为核心;
面向对象,是以“谁来解决问题”为核心。

7. 开发环境

可以看到在项目中创建并包含了两个文件:

.pro文件为项目配置文件,通常无需手动编辑,只有在项目中完全开启C++11功能时,增加下面这句话即可。

 
 
 
QMAKE_CXXFLAGS += -std=c++11

添加完成后别忘记保存

.cpp文件为C++的源代码文件,用于编写C++代码

// 头文件,标准输入输出流
// C++源码中,头文件.h以便于与C语言做区分。
#include <iostream>

// 使用标准名字空间(不要删)
using namespace std;

// 主函数,程序的入口
int main()
{
    // 连续输出一个字符串和一个换行符
    cout << "Hello World!" << endl;
    // 返回一个0
    return 0;
}
 
  1. Alt + 0 显式/隐藏边栏(有些电脑可能是win+0)
  2. ctrl+A全选,再ctrl+i对齐。 代码排版
  3. ctrl+F搜索+替换
  4. ctrl+R运行项目

二、从C到C++

本章介绍一些C++拓展的非面向对象的功能。

1. 引用(掌握)

1.1 概念

引用从一定程度上来说是指针的平替。几乎被所有的面向对象编程语言所使用。引用相当于对某一目标变量起一个“别名”。

操作引用与操作原变量完全一样

#include <iostream>


using namespace std;

int main()
{
    int a = 1;
    // b是a的引用
    int &b = a;

    cout << a << " " << &a << endl; // 1 0x61fe88
    cout << b << " " << &b << endl; // 1 0x61fe88

    return 0;
}

1.2 引用的性质

可以改变引用的值,不能再次成为其他变量的引用

声明引用先初始化不为空

可以将变量的地址赋值给指针,指针指向原来的变量

1.可以改变引用的值,但是不能再次成为其他变量的引用

#include <iostream>

using namespace std;

int main()
{
    int a = 1;
    // b是a的引用
    int &b = a;
    int c = 3;

    b = c;  // 3 只是赋值,b还是a的引用

    cout << a << " " << &a << endl; // 3 0x61fe88
    cout << b << " " << &b << endl; // 3 0x61fe88
    cout << c << " " << &c << endl; // 3 0x61fe84

    return 0;
}

2.声明引用时,必须要初始化。

#include <iostream>


using namespace std;

int main()
{
    int a = 1;
//    int &b;   // 错误,引用必须初始化
//    b = a;

    return 0;
}

3.声明引用时,不能初始化为null


#include <iostream>


using namespace std;

int main()
{
    int a = 1;
//    int &b = NULL;  // 错误,引用不能初始化为NULL

//    int &b = nullptr;   // 错误,引用不能初始化为nullptr

    return 0;
}

4.引用在声明时,初始化的值可以是纯数值,但是此时要用const关键字修饰引用,表示该引用为常量引用,这样的引用的值不可变

#include <iostream>

using namespace std;

int main()
{
    const int &b = 123; // 常量引用
//    b = 22; // 错误常量引用的值不能被改变
    cout << b << " " << &b << endl;
    return 0;
}

5.可以将变量引用的地址赋值给一个指针,此时指针指向的还是原来的变量

#include <iostream>


using namespace std;

int main()
{
    int a = 1;
    int &b = a;
    int *c = &b;    // c同时指向了A和B

    cout << a << " " << &a << endl; // 1 0x61fe84
    cout << b << " " << &b << endl; // 1 0x61fe84
    cout << *c << " " << c << endl; // 1 0x61fe84

    return 0;
}

6.可以使用const修饰引用,此时如果原变量的值改变,引用的值也改变。

#include <iostream>


using namespace std;

int main()
{
    int a = 2;
    const int &b = a;
//    b++; // 错误 b是只读的
    a++;
    cout << a << " " << &a << endl; // 3 0x61fe88
    cout << b << " " << &b << endl; // 3 0x61fe88


    const int c = 2;
    const int &d = c;
    cout << c << " " << &c << endl; // 2 0x61fe80


    return 0;
}

1.3 引用的参数

【思考】

写一个函数,函数有两个参数a和b,函数的功能交换两个传入参数原来变量的值。

#include <iostream>


using namespace std;

// 需求:写一个函数,实现参数a和b的数据交换。

// 值传递,操作的是拷贝的副本,不符合需求
void test(int a1,int b1)
{
    int temp = a1;
    a1 = b1;
    b1 = temp;

    cout << "a1 =" << a1 << endl;
    cout << "b1 =" << b1 << endl;
}

// C语言,不推荐这种写法
void test1(int *a1,int *b1)
{
    *a1 = *a1 ^ *b1;
    *b1 = *a1 ^ *b1;
    *a1 = *a1 ^ *b1;
}

// 引用传递不会产生副本。C++编程方式,符合需求
void test2(int &a1,int &b1)
{
    a1 = a1 ^ b1;
    b1 = a1 ^ b1;
    a1 = a1 ^ b1;
}

int main()
{
    int a = 1;
    int b = 2;
    test(a,b);
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;

    test1(&a,&b);
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;


    test2(a,b);
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;
    return 0;
}

引用作为参数进行定义的时候,在参数传递时,是不会产生副本的,这样会提高运行效率,我们编程中,建议使用引用进行传递参数。

引用参数,在不参数计算的情况下,我们建议使用const进行修饰,以达到引用安全的目的。

2. 赋值(熟悉)

通常编程中使用=进行赋值操作,C++新增了一些赋值语法。

#include <iostream>


using namespace std;

int main()
{
    int a(1);   // int a = 1;
    cout << a << endl;

    int b(a);
    cout << b << endl;  // int b = a;

    int c(a+b);
    cout << c << endl;  // int c = a + b;

    return 0;
}

在C++11中对上述写法又进行升级   大括号会对数据窄化做出警告。

3. 键盘输入(熟悉)

可以使用cin把用户在命令行中输入的内容赋值到变量中。

cin与cout一样,都是属于头文件iostream中的标准输入输出流。

#include <iostream>


using namespace std;

int main()
{
    int a;
    // C++的字符串
    string str;

    cout << "请输入一个数字和字符串" << endl;
    cin >> a >> str; // 接收键盘输入,一个整数和字符串,可以连续操作

    cout << a << " " << str << endl;
    return 0;
}

如果cin输入的字符串需要包含空格,则可以使用下面的方式:

#include <iostream>


using namespace std;

int main()
{
    string a; //C++的字符串类型

    cout << "请输入一个字符串,可以包含空格,输入完成后按下回车" << endl;
    getline(cin,a);
    cout << "您输入的是:" << a << endl;
    return 0;
}

4. string字符串类(掌握)

string不是C++的基本数据类型,是一个C++标准库中的字符串类,使用时需要引入头文件#include<string>,而不是string.h

string在绝大多数情况下可以代替C语言中的字符串,不必担心内存是否足够和字符串长度等问题,其中内部还包含了很多字符串处理函数,可以完成各种情况下的字符串处理功能。

string和C语言相同,字符串编码也是使用ASCII编码,不支持中文。

#include <iostream>

using namespace std;

int main()
{
    string str = "helloworld";
    cout << str.size() << endl; // 10
    cout << str.length() << endl;   // 10

    cout << str[0] << endl; // h
    cout << str.at(1) << endl;  // e

    return 0;
}

两种方式都可以,但是在C++中推荐使用at函数,原因是更加的安全。但是[ ]的方式效率更高

#include <iostream>

using namespace std;

int main()
{
    string str = "helloworld";

//    cout << str[100] << endl;   // 输出一个越界数据
//    cout << "hello" << endl;

    cout << str.at(100) << endl;    // 程序运行停止
    cout << "hello" <<endl;

    return 0;
}

string类支持很多种遍历方式

  • 普通循环(for)
  • C++11 for each循环
#include <iostream>

using namespace std;

int main()
{
    string str = "helloworld";

    for(int i = 0; i < str.size(); ++i)
    {
        cout << str.at(i);
    }
    cout << endl;
    // 以 for each的方式进行循环遍历字符串
    for(char i:str)
    {
        cout << i;
    }
    return 0;
}

5. 函数

5.1 内联函数(熟悉)

内联函数用于取代C语言中宏定义的函数,内联函数的正确使用可以体征程序的执行效率,内联函数在编译的时候,直接把函数体展开到主函数中进行编译,在运行时可以减少调用的开销。

空间换时间

通常讲具有以下性质的函数写为内联函数:

  • 代码长度5行以内。
  • 不包含复杂的控制语句
  • 调用频繁
#include <iostream>

using namespace std;

// 内联函数
inline void print_string(string str)
{
    cout << str << endl;
}
int main()
{
    print_string("helloworld");
    return 0;
}

但是我们手动添加上inline关键字,将函数声明为内联函数。这个不是我们能决定的,编译器有自己的判断准则,我们只是给编译器提一个建议。具体是否变为内联函数,还是编译器自己决定的。

后续学习的成员函数默认都添加了inline修饰。

5.2 函数重载overload(重点)

C++中允许多个函数使用同一个名称,这种用法就是函数重载,函数重载要求函数名称相同

但是参数不同(类型或者数量)或者前后顺序不同。与返回值等其他因素无关

#include <iostream>

using namespace std;



// 错误名称一样,参数类型一样,编译器无法区分
//double print_show(const int s)
//{
//    cout << "调用了int重载:" << s << endl;
//    return 1.2;
//}

void print_show(string s)
{
    cout << "调用了string重载:" << s << endl;
}

//void print_show(float f)
//{
//    cout << "调用了float重载:" << f << endl;
//}

void print_show(int i)
{
    cout << "调用了int重载:" << i << endl;
}


int main()
{
    print_show(1);
    return 0;
}

5.3 哑元函数(熟悉)

函数的参数只有类型,没有名称,有这样的参数的函数就是哑元函数。

#include <iostream>

using namespace std;

// 哑元函数
void print_show(int)
{
    cout << "调用了int函数" << endl;
}

// 错误 哑元函数无法区分函数重载
//void print_show(int i)
//{
//    cout << "调用了int i 函数" << endl;
//}

int main()
{
    print_show(1);
    return 0;
}

作用1:哑元函数用来区分函数重载

作用2:运算符重载中用到

#include <iostream>

using namespace std;

// 哑元函数
void print_show(int i,int)
{
    cout << "调用了int函数" << endl;
}

// 错误 哑元函数无法区分函数重载
void print_show(int i)
{
    cout << "调用了int i 函数" << endl;
}

int main()
{
    print_show(1);
    return 0;
}

1、键盘输入一个100-999之间的数,依次输出这个数的个十百位。

2、输入一行字符串,分别统计出其中的英文字母,数字和其他字符的个数。

#include <iostream>

using namespace std;
#if 0
int main()
{
    int a;
    cout<<"请输入一个100-999之间的数"<<endl;
    cin>>a;
    if(a>100&&a<999)
    {
        int a1=a/100;
        int a2=a/10%10;
        int a3=a%10;
        cout<<"百位:"<<a1<<"  十位:"<<a2<<"  个位:"<<a3<<endl;
    }
    else
    {
        cout<<"输入错误"<<endl;
    }
    return 0;
}
#endif

#if 1
int main()
{
    string str;
    int sum1=0,sum2=0,sum3=0;
    cout<<"请输入一个字符串:"<<endl;
    getline(cin,str);
    for(int i=0;i<str.size();++i)
    {
        if(str.at(i)>=48&&str.at(i)<=57)
        {
            sum1++;
        }
        else if((str.at(i)>=65&&str.at(i)<=90)||(str.at(i)>=97&&str.at(i)<=122))
        {
            sum2++;
        }
        else
        {
            sum3++;
        }
    }

    cout<<"数字个数:"<<sum1<<endl;
    cout<<"英文字母个数:"<<sum2<<endl;
    cout<<"其他字符个数:"<<sum3<<endl;

    return 0;
}
#endif

三、面向对象基础

1. 类对象

1.1 概念

类:抽象的概念,描述同一类对象的特点

对象:根据类的概念所创造的实体

一个对象可以没有对应类嘛?

不可以,因为必须先写类才能创建对象。

1.2 内容

类中最基础的内容包括两部分:一个是属性,一个是行为。

属性:表示一些特征项的数值,比如说:身高、体重、颜色、型号等等。而这些特征项的数值也被称为“成员变量”。属性一般以名词存在。

行为:表示能执行的动作,能干什么事?比如说:吃饭、睡觉、打架、爬山、唱、跳、rap、篮球。行为一般通过函数实现,也被称为“成员函数”。行为一般以动词存在。

成员 = 成员函数+成员变量。

#include <iostream> // 输入输出流库,用于输入和输出数据

using namespace std; // 使用标准命名空间

// 帕斯卡命名法(大驼峰命名法)
// 每个单词的首字母要大写
class MobilePhone
{
public: // 权限:public最开放的权限,表示可以在类的外部访问
    string brand;   // 手机品牌
    string model;   // 手机型号
    int weight;     // 手机重量(克)

    // 播放音乐
    void play_music()
    {
        cout << "只因你太美,哒哒哒" << endl; // 输出播放音乐的提示信息
    }

    // 运行游戏
    void run_game()
    {
        cout << "植物大战僵尸杂交版" << endl; // 输出运行游戏的提示信息
    }

    // 打电话
    void call()
    {
        cout << "哥哥~ 您在吗?" << endl; // 输出打电话的提示信息
    }
};


int main()
{

    return 0; // 返回0,表示程序正常结束
}

1.3 对象创建

C++中 存在两种类型的对象。

栈内存对象     

手动创建,对象所在的{ }执行完毕后,自动被销毁。

#include <iostream> // 输入输出流库

using namespace std; // 使用标准命名空间

// 帕斯卡命名法
class MobilePhone {

public:
    string brand; // 手机品牌
    string model; // 手机型号
    int weight;   // 手机重量(克)

    // 播放音乐
    void play_music() {
        cout << "听音乐" << endl;
    }

    // 玩游戏
    void play_game() {
        cout << "玩游戏" << endl;
    }

    // 打电话
    void call() {
        cout << "打电话" << endl;
    }
};

int main() {
    MobilePhone mp; // 创建 MobilePhone 类的对象
    mp.brand = "小米"; // 设置手机品牌为小米
    mp.model = "14ultra"; // 设置手机型号为 14ultra
    mp.weight = 200; // 设置手机重量为 200 克

    // 输出手机信息
    cout << "品牌:" << mp.brand << "  型号:" << mp.model << "  重量:" << mp.weight << "克" << endl;

    // 执行手机功能
    mp.play_music(); // 播放音乐
    mp.play_game(); // 玩游戏
    mp.call(); // 打电话

    return 0;
}

堆内存创建

必须使用new关键字创建,使用指针保存,delete关键字销毁,如果不销毁,则堆内存对象会持续存在。而堆内存泄漏。堆内存调用对象时,使用 -> 而不是.

#include <iostream> // 输入输出流库

using namespace std; // 使用标准命名空间

// 帕斯卡命名法
class MobilePhone {

public:
    string brand; // 手机品牌
    string model; // 手机型号
    int weight;   // 手机重量(克)

    // 播放音乐
    void play_music() {
        cout << "听音乐" << endl;
    }

    // 玩游戏
    void play_game() {
        cout << "玩游戏" << endl;
    }

    // 打电话
    void call() {
        cout << "打电话" << endl;
    }
};

int main() {
    MobilePhone *mp = new MobilePhone; // 创建 MobilePhone 类的对象并分配内存
    mp->brand = "三星"; // 设置手机品牌为三星
    mp->model = "Galaxy S23"; // 设置手机型号为 Galaxy S23
    mp->weight = 200; // 设置手机重量为 200 克

    // 输出手机信息
    cout << "品牌:" << mp->brand << "  型号:" << mp->model << "  重量:" << mp->weight << "克" << endl;

    // 执行手机功能
    mp->play_music(); // 播放音乐
    mp->play_game(); // 玩游戏
    mp->call(); // 打电话

    delete mp; // 释放分配的内存
    mp = NULL; // 将指针置为空

    return 0;
}

//在主函数 main 中,动态分配了一个 MobilePhone 对象,设置了其品牌、型号和重量属性,然后调用了其方法,最后释放了动态分配的内存。

2. 封装

在上一节中的手机类与结构体差别不大,实际上可以认为结构体就是一种完全开放的类。

封装指的是,将类的一些属性和细节隐藏,重新对外提供访问函数,封装可以提升代码的安全性,并且可以让程序员更关注上层架构而非内部细节。

#include <iostream> // 输入输出流库

using namespace std; // 使用标准命名空间

// 帕斯卡命名法(大驼峰命名法)
// 每个单词的首字母要大写
class MobilePhone
{
private:    // 私有权限:private最封闭的权限,只能在类内进行访问
    string brand;   // 手机品牌
    string model;   // 手机型号
    int weight;     // 手机重量(克)

public: // 权限:public最开放的权限
    // get 读函数
    string get_brand() // 获取手机品牌
    {
        return brand; // 返回手机品牌
    }

    // set 写函数
    void set_brand(string b) // 设置手机品牌
    {
        brand = b; // 将参数 b 赋值给手机品牌
    }
};


int main()
{
    MobilePhone mp1;    // 创建 MobilePhone 类的对象 mp1,在栈上分配内存
    mp1.set_brand("华为"); // 调用 set_brand 方法设置手机品牌为 "华为"
    cout <<  mp1.get_brand() << endl; // 调用 get_brand 方法获取手机品牌并输出

    MobilePhone *mp = new MobilePhone; // 创建 MobilePhone 类的对象 mp,在堆上分配内存
    mp->set_brand("菠萝手机"); // 调用 set_brand 方法设置手机品牌为 "菠萝手机"
    cout << mp->get_brand() << endl; // 调用 get_brand 方法获取手机品牌并输出

    delete mp; // 释放动态分配的内存
    mp = NULL; // 将指针置为空

    return 0; // 返回0,表示程序正常结束
}

3. 构造函数

构造函数是一种特殊的成员函数,用于创建对象时初始化,写法上有以下要求:

  • 函数名称必须与类名完全相同
  • 构造函数不写返回值
  • 如果程序员不手动编写构造函数,编译器会自动添加一个无参的构造函数,手动添加构造函数后,编译器就不会自动添加默认无参构造函数了。

3.1 基本使用

构造函数在创建对象时,常用于给对象的属性赋予初始值。

#include <iostream> // 包含输入输出流库

using namespace std; // 使用标准命名空间

// 帕斯卡命名法(大驼峰命名法)
// 每个单词的首字母要大写
class MobilePhone
{
private: // 私有权限:private 最封闭的权限,只能在类内进行访问
    string brand; // 品牌
    string modle; // 型号
    int weight;   // 重量

public: // 公有权限:public 最开放的权限,可以在类外部访问
    // 编译器自动添加的构造函数(无参构造函数)
    MobilePhone()
    {
        brand = "8848";         // 默认品牌为 "8848"
        modle = "M6巅峰版";    // 默认型号为 "M6巅峰版"
        weight = 888;           // 默认重量为 888
    }

    // get 读函数,用于获取品牌
    string get_brand()
    {
        return brand; // 返回品牌
    }

    // set 写函数,用于设置品牌
    void set_brand(string b)
    {
        brand = b; // 设置品牌
    }
};

int main()
{
    MobilePhone mp1;    // 在栈内存中创建一个 MobilePhone 对象 mp1
    cout << mp1.get_brand() << endl; // 调用对象的 get_brand() 方法,打印品牌信息

    return 0; // 返回 0,表示程序成功结束
}

造函数也支持重载

#include <iostream> // 包含输入输出流库

using namespace std; // 使用标准命名空间

// 帕斯卡命名法(大驼峰命名法)
// 每个单词的首字母要大写
class MobilePhone
{
private: // 私有权限:private 最封闭的权限,只能在类内进行访问
    string brand; // 品牌
    string modle; // 型号
    int weight;   // 重量

public: // 公有权限:public 最开放的权限,可以在类外部访问
    // 编译器自动添加的构造函数(无参构造函数)
    MobilePhone()
    {
        brand = "8848";         // 默认品牌为 "8848"
        modle = "M6巅峰版";    // 默认型号为 "M6巅峰版"
        weight = 888;           // 默认重量为 888
    }

    // 有参构造函数
    MobilePhone(string b, string m, int w)
    {
        brand = b;  // 使用传入的参数值初始化品牌
        modle = m;  // 使用传入的参数值初始化型号
        weight = w; // 使用传入的参数值初始化重量
    }

    // get 读函数,用于获取品牌
    string get_brand()
    {
        return brand; // 返回品牌
    }

    // set 写函数,用于设置品牌
    void set_brand(string b)
    {
        brand = b; // 设置品牌
    }
};


int main()
{
    // 在栈内存中创建一个 MobilePhone 对象 mp1,并使用有参构造函数初始化
    MobilePhone mp1("金立", "老年机", 400);
    cout << mp1.get_brand() << endl; // 调用对象的 get_brand() 方法,打印品牌信息

    // 在栈内存中创建一个 MobilePhone 对象 mp2,并使用无参构造函数初始化
    MobilePhone mp2;
    cout << mp2.get_brand() << endl; // 调用对象的 get_brand() 方法,打印品牌信息

    // 在堆内存中动态创建一个 MobilePhone 对象,使用无参构造函数初始化,并返回指向该对象的指针
    MobilePhone *mp3 = new MobilePhone;
    cout << mp3->get_brand() << endl; // 通过指针调用对象的 get_brand() 方法,打印品牌信息
    delete mp3; // 释放动态分配的内存

    // 在堆内存中动态创建一个 MobilePhone 对象,使用有参构造函数初始化,并返回指向该对象的指针
    MobilePhone *mp4 = new MobilePhone("1加", "Ace", 100);
    cout << mp4->get_brand() << endl; // 通过指针调用对象的 get_brand() 方法,打印品牌信息
    delete mp4; // 释放动态分配的内存

    return 0; // 返回 0,表示程序成功结束
}

构造函数也支持函数默认值参数

#include <iostream> // 包含输入输出流库

using namespace std; // 使用标准命名空间

// 帕斯卡命名法(大驼峰命名法)
// 每个单词的首字母要大写
class MobilePhone
{
private: // 私有权限:private 最封闭的权限,只能在类内进行访问
    string brand; // 品牌
    string modle; // 型号
    int weight;   // 重量

public: // 公有权限:public 最开放的权限,可以在类外部访问
    // 有参构造函数,带有默认参数值
    MobilePhone(string b = "oppo", string m = "锤子", int w = 200)
    {
        brand = b;    // 使用传入的参数值初始化品牌,如果没有传入参数,则使用默认值 "oppo"
        modle = m;    // 使用传入的参数值初始化型号,如果没有传入参数,则使用默认值 "锤子"
        weight = w;   // 使用传入的参数值初始化重量,如果没有传入参数,则使用默认值 200
    }

    // get 读函数,用于获取品牌
    string get_brand()
    {
        return brand; // 返回品牌
    }

    // set 写函数,用于设置品牌
    void set_brand(string b)
    {
        brand = b; // 设置品牌
    }
};

int main()
{
    // 创建一个 MobilePhone 对象 mp2,没有传入参数,使用默认参数值初始化
    MobilePhone mp2;
    cout << mp2.get_brand() << endl; // 调用对象的 get_brand() 方法,打印品牌信息

    return 0; // 返回 0,表示程序成功结束
}

3.2 构造初始化列表

构造初始化列表是一种更简单的给成员变量赋予初始值的方式。

#include <iostream> // 包含输入输出流库

using namespace std; // 使用标准命名空间

// 帕斯卡命名法(大驼峰命名法)
// 每个单词的首字母要大写
class MobilePhone
{
private:    // 私有权限:private 最封闭的权限,只能在类内进行访问
    string brand;   // 品牌
    string modle;   // 型号
    int weight;     // 重量

public: // 公有权限:public 最开放的权限,可以在类外部访问

    // 无参构造函数
    MobilePhone() : brand("8848"), modle("M6巅峰版"), weight(888)
    {
        cout << "无参构造函数" << endl; // 输出提示信息
    }

    // 有参构造函数
    MobilePhone(string b, string m, int w)
        : brand(b), modle(m), weight(w) // 使用初始化列表初始化成员变量
    {
        cout << "有参构造函数" << endl; // 输出提示信息
    }

    // get 读函数,返回品牌
    string get_brand()
    {
        return brand; // 返回品牌
    }

    // set 写函数,设置品牌
    void set_brand(string b)
    {
        brand = b; // 设置品牌
    }
};

int main()
{
    // 使用有参构造函数创建对象 mp2
    MobilePhone mp2("小米", "红米", 200);
    // 输出 mp2 的品牌
    cout << mp2.get_brand() << endl;

    // 使用无参构造函数创建对象 mp3
    MobilePhone mp3;
    // 输出 mp3 的品牌
    cout << mp3.get_brand() << endl;

    return 0; // 返回 0,表示程序成功结束
}

当构造函数的局部变量与成员变量重名时,除了使用后面学习的this指针的方式外,也可以使用构造初始化列表的方式区分。

    // 使用初始化列表区分成员变量和参数
    MobilePhone(string brand, string modle, int weight)
        : brand(brand), modle(modle), weight(weight) {
        cout << "有参构造函数" << endl;
    }

3.3 隐式调用构造函数熟悉)

构造函数的调用方式分为显式调用隐式调用

显式调用指的是在创建对象时手写构造函数的名称。

隐式调用构造函数指的是创建对象时不写构造函数名称和参数列表,编译器会尝试调用对应参数的构造函数。

#include <iostream> // 包含输入输出流库

using namespace std; // 使用标准命名空间

class Student
{
private:
    int age; // 私有成员变量,表示学生的年龄
public:
    // 显式构造函数,使用 explicit 关键字
    explicit Student(int a) : age(a)
    {
        cout << "构造函数" << endl; // 在构造函数中输出提示信息
    }

    // 获取学生年龄的成员函数
    int get_age()
    {
        return age; // 返回学生的年龄
    }
};

int main()
{
    // 显式调用构造函数创建一个 Student 对象 s1,传入参数为 1
    Student s1(1);
    cout << s1.get_age() << endl; // 打印 s1 对象的年龄

    // 显式调用构造函数创建一个临时的 Student 对象,传入参数为 14,并将其赋值给 s3 对象
    Student s3 = Student(14);
    cout << s3.get_age() << endl; // 打印 s3 对象的年龄

    // 隐式调用构造函数创建一个临时的 Student 对象,传入参数为 15,并将其赋值给 s4 对象
    Student s4 = 15;
    cout << s4.get_age() << endl; // 打印 s4 对象的年龄

    // 显式调用构造函数创建一个动态分配的 Student 对象 s2,传入参数为 13
    Student *s2 = new Student(13);
    cout << s2->get_age() << endl; // 打印 s2 指向的对象的年龄
    delete s2; // 释放动态分配的内存
    s2 = NULL; // 将指针置为空指针,避免出现悬空指针的情况
    return 0; // 返回 0,表示程序成功结束
}

建议使用显式调用,可以使用explicit关键字来屏蔽隐式调用语法。

3.4 构造拷贝函数

当程序员不手写拷贝构造函数时,编译器会自动添加一个拷贝构造函数,使对象创建可以通过这个构造函数进行实现。

#include <iostream> // 包含输入输出流库

using namespace std; // 使用标准命名空间

class MobilePhone { // 定义一个名为 MobilePhone 的类
private:
    string brand; // 私有成员变量,表示手机品牌
    string modle; // 私有成员变量,表示手机型号
    int weight;   // 私有成员变量,表示手机重量

public:
    // 使用初始化列表的构造函数,用于初始化手机品牌、型号和重量
    MobilePhone(string brand, string modle, int weight)
        : brand(brand), modle(modle), weight(weight) {} // 初始化列表

    // 手动编写的拷贝构造函数
    MobilePhone(const MobilePhone &mp) {
        brand = mp.brand;    // 将拷贝对象的 brand 值赋给新对象的 brand
        modle = mp.modle;    // 将拷贝对象的 modle 值赋给新对象的 modle
        weight = mp.weight;  // 将拷贝对象的 weight 值赋给新对象的 weight
    }

    // 成员函数,用于显示手机信息
    void show() {
        cout << brand << " " << modle << " " << weight << " " << endl; // 输出手机品牌、型号和重量
    }
};

int main() {
    // 创建一个 MobilePhone 对象 mp1,并初始化为 "vivo", "iqoo", 230
    MobilePhone mp1("vivo", "iqoo", 230);

    // 使用拷贝构造函数创建一个新的 MobilePhone 对象 mp2,拷贝自 mp1
    MobilePhone mp2(mp1);

    // 调用 mp2 的 show 函数,显示 mp2 的信息
    mp2.show();

    return 0; // 返回 0,表示程序成功结束
}

思考:拷贝构造函数会存在隐患嘛?

存在,当成员变量出现指针类型时,默认的拷贝构造函数会导致两个对象的成员变量指向同一处,不符合面向对象的设计规范,这种现象被称为“浅拷贝”。

#include <iostream> // 包含输入输出流库
#include <string.h> // 包含字符串操作函数库

using namespace std; // 使用标准命名空间

class Dog
{
private:
    char *name; // 用于存储狗的名字的指针
public:
    // 有参构造函数
    Dog(char *n)
    {
        name = n; // 将参数 n 的地址赋值给 name,浅拷贝,只是复制指针的值
    }

    // 显示狗的名字和指针地址
    void show_name()
    {
        cout << name << endl; // 打印名字
        cout << (int *)name << endl; // 打印指针地址
    }
};

int main()
{
    char arr[20] = "旺财"; // 创建一个字符数组并初始化为 "旺财"
    Dog d1(arr); // 使用字符数组创建一个 Dog 对象 d1
    Dog d2(d1); // 使用拷贝构造函数创建另一个 Dog 对象 d2

    strcpy(arr, "大黄"); // 将字符数组的内容改为 "大黄"
    d1.show_name(); // 打印 d1 的名字和指针地址
    d2.show_name(); // 打印 d2 的名字和指针地址

    return 0; // 返回 0,表示程序成功结束
}
  1. 创建对象 d1

    • d1 被初始化时,name 指向 arr 数组的首地址。

  2. 拷贝构造函数创建对象 d2

    • 使用浅拷贝,d2name 也指向 arr 数组的首地址。

  3. 修改 arr 的内容:

    • arr 改为 "大黄" 后,d1d2name 都指向这个数组,因此它们的 name 内容都变成了 "大黄"。

  4. 显示 d1d2 的名字和指针地址:

    • d1.show_name()d2.show_name() 打印出的名字都变成了 "大黄"。

    • 打印的指针地址是相同的,因为 d1d2name 都指向 arr

输出结果
大黄
0x7ffdecd4b3c0
大黄
0x7ffdecd4b3c0

 这种情况必须手动重写拷贝构造函数,使每次赋值都创建一个新的副本,从而每个对象单独持有自己的成员变量。这种方式被称为“深拷贝”。

#include <iostream> // 包含输入输出流库
#include <string.h> // 包含字符串操作函数库

using namespace std; // 使用标准命名空间

class Dog
{
private:
    char *name; // 用于存储狗的名字的指针
public:
    // 有参构造函数
    Dog(char *n)
    {
        name = new char[20]; // 为 name 分配动态内存
        strcpy(name, n); // 将传入的名字复制到动态分配的内存中
    }

    // 拷贝构造函数
    Dog(const Dog &d)
    {
        name = new char[20]; // 为新对象的 name 分配动态内存
        strcpy(name, d.name); // 将原对象的名字复制到新对象的动态分配的内存中
    }

    // 显示狗的名字和指针地址
    void show_name()
    {
        cout << name << endl; // 打印名字
        cout << (int *)name << endl; // 打印指针地址
    }

    // 析构函数,用于释放动态分配的内存
    ~Dog()
    {
        delete[] name; // 释放动态分配的内存
    }
};

int main()
{
    char arr[20] = "旺财"; // 创建一个字符数组并初始化为 "旺财"
    Dog d1(arr); // 使用字符数组创建一个 Dog 对象 d1
    Dog d2(d1); // 使用拷贝构造函数创建另一个 Dog 对象 d2

    strcpy(arr, "大黄"); // 将字符数组的内容改为 "大黄"
    d1.show_name(); // 打印 d1 的名字和指针地址
    d2.show_name(); // 打印 d2 的名字和指针地址

    return 0; // 返回 0,表示程序成功结束
}

【思考】深拷贝的代码是否存在隐患?

存在,new开辟的空间无法释放,造成内存泄漏的问题。

4. 析构函数

析构函数是与构造函数对立的函数

构造函数

析构函数

创建对象时手动调用

对象销毁时,自动调用

函数名称是类名

函数名称是~类名

构造函数是可以重载

析构函数没有参数,不能重载

用于创建对象时并初始化

用于销毁对象时释放资源

不写返回值

没有返回值

#include <iostream>
#include <string.h>

using namespace std;

// 定义一个 Dog 类
class Dog
{
private:
    char *name; // 用于存储狗的名字的指针

public:
    // 有参构造函数,用于初始化 Dog 对象
    Dog(char *n)
    {
        // 为名字分配20个字符的动态内存
        name = new char[20];
        // 将传入的名字复制到分配的内存中
        strcpy(name, n);
    }

    // 拷贝构造函数,用于初始化一个新的 Dog 对象,使其与现有对象相同
    Dog(const Dog &d)
    {
        // 为名字分配20个字符的动态内存
        name = new char[20];
        // 将现有对象的名字复制到新对象中
        strcpy(name, d.name);
    }

    // 展示狗的名字
    void show_name()
    {
        // 输出狗的名字
        cout << name << endl;
        // 输出名字指针的地址
        cout << reinterpret_cast<void*>(name) << endl;
    }

    // 析构函数,用于清理资源
    ~Dog()
    {
        cout << "我被调用了" << endl;
        // 释放分配的内存
        delete [] name;
    }
};

int main()
{
    // 定义一个字符数组并初始化为 "旺财"
    char arr[20] = "旺财";
    
    // 使用 arr 初始化 Dog 对象 d1,调用有参构造函数
    Dog d1(arr);
    
    // 使用 d1 初始化 Dog 对象 d2,调用拷贝构造函数
    Dog d2(d1);

    // 修改字符数组 arr 的内容为 "大黄"
    strcpy(arr, "大黄");
    
    // 展示 d1 对象的名字,预期输出 "旺财"
    d1.show_name();
    
    // 展示 d2 对象的名字,预期输出 "旺财"
    d2.show_name();

    // 当 main 函数结束时,d1 和 d2 的析构函数将被自动调用
    return 0;
}

5. 作用域限定符

5.1 名字空间(熟悉)

#include <iostream>

using namespace std;

namespace my_space
{
    int a = 3;
    int b = 4;
}
using namespace my_space;

int a = 2;
int main()
{
    int a = 1;
    cout << a << endl;  // 就近原则,打印1
    cout << ::a << endl;    // ::是匿名名字空间 2
    cout << my_space::a << endl;    // 3
    cout << b << endl;  // 4

    return 0;
}

5.2 类内声明,类外定义(掌握)

#include <iostream>

using namespace std;

class Demo
{
public:
    Demo();
    void test(string str);
};


Demo::Demo()
{
    cout << "创建了一个对象" << endl;
}

void Demo::test(string str)
{
    cout << str << endl;
}

int main()
{
    Demo d;
    d.test("hello");

    return 0;
}

6.this指针(掌握)

6.1 概念

this指针是一个特殊的指针,指向当前对象的首地址。

成员函数(包括构造函数与析构函数)中都有this指针,因此this指针只能在类内使用。

实际上this指针指向的就是当前运行的成员函数所绑定的对象。

#include <iostream>

using namespace std;

class Test
{
public:
    void test_this()
    {
        cout << this << endl;
    }
};

int main()
{
//变量 t1 在栈上分配
    Test t1;
    cout << &t1 << endl;    // 0x61fe8f
    t1.test_this(); // 0x61fe8f

//变量 t2 在堆上分配
    Test *t2 = new Test;
    cout << t2 << endl; // 0xf62740
    t2->test_this();    // 0xf62740
    delete t2;

    return 0;
}

6.2 this指针功能

6.2.1 类内调用成员

成员(变量+函数)必须由对象调用。类中成员的调用都依赖于this指针,通常由编译器自动添加。

#include <iostream>

using namespace std;

class Test
{
private:
    string name;
public:
    Test(string n)
    {
        // 编译器默认添加this指针,指向的对象调用成员
        this->name = n;
    }
    void test_this()
    {
        cout << this << endl;
    }

    string get_name()
    {
        return this->name;
    }
};

int main()
{
    Test t1("zhangsan");
    cout << t1.get_name() << endl;

    Test t2("lisi");
    cout << t2.get_name() << endl;

    return 0;
}
6.2.2 区分重名的成员变量和局部变量
#include <iostream>

using namespace std;

class Test
{
private:
    string name;
public:
    Test(string name):name(name) // 构造初始化列表区分
    {
        // 通过this指针在函数体中区分
//        this->name = name;
    }
    void test_this()
    {
        cout << this << endl;
    }

    string get_name()
    {
        return this->name;
    }
};

int main()
{
    Test t1("zhangsan");
    cout << t1.get_name() << endl;

    Test t2("lisi");
    cout << t2.get_name() << endl;

    return 0;
}
6.2.3 链式调用

支持链式调用的成员函数特点:

  1. 当一个成员函数的返回值是当前类型的引用时,往往表示这个函数支持链式调用。
  2. return后面是*this
#include <iostream>

using namespace std;

class Test
{
private:
    int val = 0;
public:
    Test& add(int i)
    {
        val += i;   // val = val + i;
        return *this;   // this是一个指针,需要取内容返回对象的引用
    }

    int get_val()
    {
       return val;
    }
};

int main()
{
    Test t1;
    t1.add(1);
    t1.add(2);
    t1.add(100);
    cout << t1.get_val() << endl;

    Test t2;
    // 链式调用
    cout << t2.add(2).add(21).add(200).get_val() << endl;
    cout << t2.get_val() << endl;
    return 0;
}

7. static关键字(掌握)

7.1 静态局部变量

使用static修饰局部变量,这样的变量就是静态局部变量。

静态局部变量在第一次调用时创建,直到程序结束后销毁,同一个类的所有对象共用这一份静态局部变量。

#include <iostream>

using namespace std;

class Test
{
public:
    void func()
    {
        int a = 1;
        static int b = 1;   // 静态局部变量
        cout << "a=" << ++a << " " << &a << endl;
        cout << "b=" << ++b << " " << &b << endl;
    }
};

int main()
{
    Test t1;
    t1.func();

    t1.func();

    Test t2;
    t2.func();
    t2.func();

    return 0;
}

7.2 静态成员变量

使用static修饰成员变量,这样的变量就是静态成员变量。

静态成员变量需要在类内声明,类外初始化。

一个类的所有对象共用一份静态成员变量,虽然静态成员变量可以使用对象调用,但是更简易直接使用类名调用。所以静态成员变量可以脱离对象使用,在程序开始运行时就开辟内存直到程序运行结束销毁。

更推荐使用类名进行调用,代码的可读性更好。

#include <iostream>

using namespace std;

class Test
{
public:
    int a = 1;
//    static int b = 2; // 错误,静态成员变量需要类内声明,类外初始化
    static int b;

};

int Test::b = 1;    // 静态成员变量类外初始化

int main()
{
    // 脱离对象使用
    cout << Test::b << " " << &Test::b << endl;
    Test t1,t2;
    cout << t1.a++ << " " << &t1.a << endl; // 1 0x61fe8c
    cout << t2.a++ << " " << &t2.a << endl; // 1 0x61fe88

    cout << t1.b++ << " " << &t1.b << endl; // 1 0x403004
    cout << t2.b++ << " " << &t2.b << endl; // 2 0x403004

    cout << Test::b << " " << &Test::b << endl; // 3 0x403004
    return 0;
}

7.3 静态成员函数

使用static修饰成员函数,这样的函数就是静态成员函数。

与静态成员变量相似的有:

都可以通过类名直接调用,也可以通过对象调用。(推荐使用类名直接调用)。

都可以脱离对象使用。

静态成员函数没有this指针,不能在静态成员函数中调用同类其他非静态成员,但是静态成员函数可以调用静态成员。

#include <iostream>

using namespace std;

class Test
{
public:
    void func()
    {
//        func1(); // 非静态成员函数可以调用静态成员函数
        cout << "非静态成员函数" << endl;
    }

    static void func1()
    {
//        func(); // 错误,静态成员函数,不能调用非静态成员函数
        cout << "静态成员函数" << endl;
    }

    static void func2()
    {
        func1();
        cout << "静态成员函数2" << endl;
    }
};


int main()
{
//    Test::func1();
    Test t1;
//    t1.func();
    t1.func2();


    return 0;
}


如果要在静态成员函数内调用非静态成员的属性。可以通过参数将对象传递进来,因为静态成员函数没有this指针。也可以在函数内部创建新的对象。例如:

#include <iostream>

using namespace std;

class Test
{
public:
    void func()
    {
//        func1(); // 非静态成员函数可以调用静态成员函数
        cout << "非静态成员函数" << endl;
    }

    static void func1()
    {
        Test t2;
        t2.func(); // 错误,静态成员函数,不能调用非静态成员函数
        cout << "静态成员函数" << endl;
    }

    static void func2()
    {
//        func1();
        cout << "静态成员函数2" << endl;
    }
};


int main()
{
//    Test::func1();
    Test t1;
    t1.func1();
    t1.func2();


    return 0;
}

7.4 单例设计模式(了解)

设计模式是一套被反复是使用,多人知晓的、经过分类的、代码设计经验的总结。通常用于一些面向对象的语言,如Java、C++、C#等等。

本节以一个简化版本的单例设计模式为例,讲解static的实际使用

#include <iostream>

using namespace std;

// 单例设计模式
class Singleton
{
private:
    Singleton(){}
    Singleton(const Singleton &sing){}
    static Singleton *instance; // 静态成员变量

public:
    static Singleton *get_instance()
    {
        if(instance == NULL)
        {
            instance = new Singleton;
        }
        return instance;
    }

    static void delete_instance()
    {
        if(instance != NULL)
        {
            delete instance;
            instance = NULL;
        }
    }
};
Singleton *Singleton::instance = NULL;

int main()
{
    Singleton *s1 = Singleton::get_instance();
    cout << s1 << endl;
    Singleton *s2 = Singleton::get_instance();
    cout << s2 << endl;

    return 0;
}

8. const关键字(掌握)

8.1 const修饰成员函数

const修饰的成员函数,表示常成员函数。

特性如下:

可以调用成员变量,但是不能修改成员变量的值。

不能调用非const修饰的成员函数,哪怕这个函数没有修改成员变量。

建议只要成员函数不修改成员变量就使用const修饰,例如show函数get等等。

8.2 const修饰对象

const修饰的对象被称为常量对象,这种对象的成员变量值无法修改,可以调用,也无法调用非const修饰的成员函数。

#include <iostream>

using namespace std;

class Demo
{
private:
    int a;
public:
    int b = 10;
    Demo(int a)
    {
        this->a = a;
    }

    void func0()
    {
        cout << "普通成员函数" << endl;
    }

    int get_demo()const
    {
        return a;
    }

    void test() const   // 常成员函数
    {
//        a++; // 错误const 修饰的成员函数,不能修改成员变量
        cout << a << endl; // 可以调用,但是不能修改
//        func0(); // 错误const修饰的成员函数,不能调用非const修饰的成员函数
        get_demo();
    }
};

int main()
{
    const Demo demo(1);
//    Demo const demo(1);  // 两种初始化方式,等效于上一行。

    cout << demo.get_demo() << endl;
//    demo.func0(); // 错误 const修饰的对象,无法调用非const成员函数
    demo.test();
    cout << demo.b << endl;
//    demo.b = 20; // 可以调用但是不能修改成员变量的值

    return 0;
}

8.3 const修饰成员变量

const修饰的成员变量为常成员变量,表示该成员变量的值无法被修改。

常成员变量有两种初始化方式:

  • 直接赋值   声明后赋值
  • 构造初始化列表

同时使用时,前者失效,以后者为准。

#include <iostream>

using namespace std;

class Demo
{
private:
    const int a = 1;    // 直接赋值
    const int b = 2;
    const int c = 3;
public:
    Demo(int a,int b,int c):a(a),b(b),c(c)
    {
//        this->a = 100; // const修饰的成员变量,值无法修改
    }

    void show()
    {
        cout << a << " " << b << " " << c << endl;
    }

    void test()
    {
//        a++;  错误const修饰的成员变量,可以调用但是不能修改。
//        b++;
//        c++;
    }
};

int main()
{
    Demo d(10,20,30);
    d.show();

    return 0;
}

8.4 const修饰局部变量

const修饰局部变量,表示该变量无法被修改。

这种方式常用于引用参数。

#include <iostream>

using namespace std;

class Demo
{
private:
    const int a = 1;    // 直接赋值
    const int b = 2;
    const int c = 3;
public:
    Demo(int a,int b,int c):a(a),b(b),c(c)
    {
//        this->a = 100; // const修饰的成员变量,值无法修改
    }

    void show()
    {
        cout << a << " " << b << " " << c << endl;
    }

    void test()
    {
        int e = 1;
        e = 10;
        cout << e << endl;


        const int f = 1;
//        f = 10;
        cout << f << endl;
    }
};

int main()
{
    Demo d(10,20,30);
    d.show();
    d.test();

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2082642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

获取文件属性/库Lib

获取文件属性 stat 函数 man 2 stat #include <sys/types.h> #include <sys/stat.h> #include <unistd.h>int stat(const char *path, struct stat *buf); 功能&#xff1a;获取文件属性 参数&#xff1a; path&#xff1a;文件路径名buf&#xff1a;保存文…

最新黑名单查询录入系统_全开源源码

最新黑名单查询录入系统_全开源源码 前端html 后端layui 操作部分都采用API接口的方式实线 集结了layui表格的多数据操作&#xff0c;添加&#xff0c;批量删除&#xff0c;分页&#xff0c;单项删除 后台数据修改采用绑定参数的形式来进行修改可以很好的预防数据库注入…

【Python入门】第3节 循环语句

&#x1f4d6;第3节 循环语句 ✅while循环的基础语法✅while循环的嵌套✅while循环的嵌套案例✅for循环的基础语法&#x1f9ca;基础语法&#x1f9ca;range语句&#x1f9ca;变量作用域 ✅for循环的嵌套应用✅循环中断 : break和continue ✅while循环的基础语法 只要条件满足…

Thread的属性和方法及如何中断一个线程

文章目录 一. Thread提供的属性和方法1. Thread常见的构造方法2. 属性及获取方法 二. 中断(终止)一个线程1) 自己来实现控制线程结束的例子2) 使用Thread提供的interrupt和isInterrupted方法来实现控制线程结束 一. Thread提供的属性和方法 1. Thread常见的构造方法 ③ 在创建…

戏曲多多 v1.0.4 — 专为老年人打造的戏曲娱乐软件(含经典评书与广场舞)

戏曲多多 TV 是一款专为老年人量身打造的视频娱乐软件&#xff0c;安装在智能电视、智能机顶盒、投影仪等安卓系统设备上后&#xff0c;老年人可以在电视上轻松观看各种戏曲视频。软件涵盖豫剧、京剧、秦腔、越剧、昆曲、淮剧、川剧、黄梅戏等多种戏曲类型。除了戏曲&#xff0…

Java设计模式之原型模式详细讲解和案例示范

引言 在软件设计中&#xff0c;设计模式为我们提供了可复用的解决方案&#xff0c;以应对常见的设计问题。原型模式&#xff08;Prototype Pattern&#xff09;是创建型设计模式的一种&#xff0c;它允许通过复制现有对象来创建新对象&#xff0c;而不需要了解创建过程的细节。…

【软件】常用软件教程一:码云(Gitee)使用方法

文章目录 一、简介二、创建远程仓库三、配置SSH公钥四、同步 Gitee 仓库内容到本地五、本地新建文件并同步至 Gitee六、删除远程仓库中的指定文件七、常见代码 一、简介 Git 是一种分布式版本控制系统&#xff0c;用于跟踪和管理代码的变更。它是由 Linus Torvalds 创建的&…

ctfhub-web-SSRF(内网访问-上传文件)

www.ctfhub.com less-1 内网访问 步骤一&#xff1a;开启环境&#xff0c;查看提示 步骤二&#xff1a;输入urlhttp://127.0.0.1/flag.php 得出结果 显示提交成功 less-2 伪协议读取文件 步骤一&#xff1a;开启环境&#xff0c;查看提示 步骤二&#xff1a;输入urlfile://…

英伟达财报引爆AI投资狂潮?华尔街众说纷纭

英伟达&#xff0c;这个名字最近可是火爆了整个科技圈。作为全球最大的GPU供应商&#xff0c;英伟达的每一次动作都牵动着无数投资者的神经。尤其是即将到来的财报发布&#xff0c;更是让市场充满了期待和忐忑。 华尔街聚焦&#xff1a;AI巨头能否持续高增长&#xff1f; 整个…

背完这些软件测试核心面试题,offer轻松拿捏了!

你赞同过 软件测试和开发 相关内容 01、您所熟悉的测试用例设计方法都有哪些&#xff1f;请分别以具体的例子来说明这些方法在测试用例设计工作中的应用。 答&#xff1a;有黑盒和白盒两种测试种类&#xff0c;黑盒有等价类划分法&#xff0c;边界分析法&#xff0c;因果图法…

NVDA财报公布在即,港股围观情绪明显

港股上午盘三大指数低开低走&#xff0c;恒生科技指数一度大跌1.59%&#xff0c;恒指再度失守17800点。盘面上&#xff0c;大型科技股全线下跌令大市承压&#xff0c;百度跌超3%&#xff0c;网易、美团跌超2%&#xff0c;腾讯、快手、阿里巴巴跌超1%&#xff1b;多家房企宣布营…

Git学习(001 git介绍以及安装)

尚硅谷2024最新Git企业实战教程&#xff0c;全方位学习git与gitlab 总时长 5:42:00 共40P 此文章包含第1p-第p4的内容 文章目录 介绍Git介绍GitLab介绍 概述Git安装版本控制工具介绍 介绍 Git介绍 GitLab介绍 相当于中央仓库 概述 Git安装 进入官网(下载当前版本 2.43.0) …

JavaScript ES6+ 新特性

JavaScript ES6 新特性 引言 随着前端技术的不断发展&#xff0c;JavaScript 语言也在不断演进。自 ES6&#xff08;ES2015&#xff09;发布以来&#xff0c;JavaScript 引入了许多新的特性和语法&#xff0c;极大地提升了开发者的编程体验和代码的可维护性。本篇文章将详细探…

测试必备--轻松掌握弱网测试技巧

在如今的移动互联网时代,用户对应用的依赖性越来越强。然而,网络环境并非总是理想的,特别是在信号较弱或网络不稳定的情况下,应用的表现尤为重要。你是否曾遇到过这样的情况:在地铁、地下停车场或者偏远地区,网络信号减弱,应用频繁卡顿甚至崩溃?为了确保用户在弱网环境…

JS WebSocket 深度解析

JS WebSocket 深度解析 文章目录 JavaScript WebSocket 深度解析一、WebSocket 是什么二、JS 中如何使用 WebSocket1. 创建 WebSocket 对象2. 连接打开事件3. 监听消息事件4. 监听错误事件5. 关闭连接 三、WebSocket 包含哪些属性或方法 API1. 属性2. 方法 四、扩展与高级技巧1…

微分方程(Blanchard Differential Equations 4th)中文版Section4.5

塔科马海峡大桥 1940年7月1日,耗资600万美元的塔科马海峡大桥正式通车。仅仅四个月后的11月7日,在一场风暴中,这座桥解体并倒塌。这座悬索桥全长超过一英里,曾在它短暂的使用期内因桥面在风中剧烈摆动而被称为“跳跃的格蒂”(Galloping Gertie)。大桥的倒塌不仅成为一场…

KAN+Transformer,一个快速发论文的新创新点!

KAN爆火至今&#xff0c;关于它和Transformer谁更强的问题还没定论&#xff0c;这俩结合的工作效果却愈发出众了&#xff0c;短时间内就有了不少高质量论文发表。 不得不说&#xff0c;这是一种富有创新性的尝试&#xff0c;利用了KAN的灵活性和可解释性&#xff0c;以及Trans…

ocr识别遇到的问题(nested exception is java.lang.UnsatisfiedLinkError)

目录 前言&#xff1a; 问题描述&#xff1a; 解决思路&#xff1a; 解决方法&#xff1a; 总结反思&#xff1a; 前言&#xff1a; 上篇讲过我使用冰蓝的jar包在Java 项目中扫描识别图片中的文字&#xff0c;这篇写更新上线中遇到的问题。 问题描述&#xff1a; 项目打…

c++习题26-大整数加法

目录 一&#xff0c;题目 二&#xff0c;思路 三&#xff0c;代码 一&#xff0c;题目 描述 求两个不超过200位的非负整数的和。 输入 有两行&#xff0c;每行是一个不超过200位的非负整数&#xff0c;可能有多余的前导0。 输出 一行&#xff0c;即相加后的结果。结果里不…

论文合作容易踩坑?学术大咖为你揭秘合作研究中的潜规则

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 知乎上的话题&#xff0c;引发大家热议。因为如今合作发表论文在学术圈越来越普遍了。 随着低垂果实都发表了&#xff0c;大家在自己的领域越做越细分&#xff0c;再加上人工智…