【浅尝C++】类和对象第二弹=>类的6个默认成员函数/运算符重载详谈

2024-03-26 03:36

本文主要是介绍【浅尝C++】类和对象第二弹=>类的6个默认成员函数/运算符重载详谈,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

🏠专栏介绍:浅尝C++专栏是用于记录C++语法基础、STL及内存剖析等。
🚩一些备注:之前的文章有点杂乱,这里将前面的知识点重新组织了,避免了过多冗余的废话。
🎯每日努力一点点,技术变化看得见。

文章目录

  • 类的6个默认成员函数概述
  • 构造函数
    • 概念
    • 特性
  • 析构函数
    • 概念
    • 特性
  • 拷贝构造函数
    • 概念
    • 特性
  • 赋值运算符重载
    • 运算符重载
    • 赋值运算符重载
    • 前置++与后置++
  • const成员
  • 取地址及const取地址操作符重载


类的6个默认成员函数概述

如果我们写一个不含任何成员函数、成员变量的类,这个类什么成员都没有,则称这个类为空类

class Date{};

空类真的什么都没有吗?并不是!任何类在什么都不写的情况下,编译器会自动生成下图所示的6个默认成员函数。

在这里插入图片描述
上面说的默认成员函数,就是用户没有显示实现,编译器会生成的成员函数称为默认成员函数。

构造函数

概念

首先,我们来看一个日期类代码↓↓↓

class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Init(2024, 5, 5);d1.Print();return 0;
}

上面代码中,我们在实例化一个Date对象d1后,如果想对它的3个成员变量进行初始化,需要显示调用Init函数进行初始化。我们在定义一个类型/一个对象时,经常都需要对它进行初始化,如果每次都需要显示调用初始化函数显然有点麻烦。

那能否在对象创建的时候,直接将初始值设置进去呢?这就需要谈谈C++类和对象中的析构函数了。

构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次

特性

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象

其特性如下:

  1. 函数名与类名相同
  2. 无返回值
  3. 对象实例化时编译器自动调用对应的构造函数
  4. 构造函数可以重载【也就是说,一个类可以有多个构造函数】

下面定义一个提供默认构造函数的日期类,演示上面的4个特性↓↓↓

#include <iostream>
using namespace std;class Date
{
public://无参构造函数 --> 函数名与类名相同,无返回值Date(){}//有参构造函数 --> 与无参构造函数构成重载Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024,5,5);//编译器在对象创建时自动调用有参构造函数Date d2;//编译器在对象创建时自动调用无参构造函数return 0;
}

上面代码中需要特别注意的是,在调用无参构造函数时,需要在对象的后面添加括号。否则编译器会将这种代码看作函数的声明。

void test()
{Date d3();//编译器会将该行代码看作函数名为d3,返回值为Date,没有的参数的函数声明Date d4;//调用无参构造不用在对象后面加括号
}
  1. 如果类没有定义构造函数,则C++编译器会自动生成一个无参的默认构造函数。但只要用户显示定义构造函数数(不管是有参构造还是无参构造),编译器将不再生成默认构造函数。
#include <iostream>
using namespace std;class Date
{
public://用户定义了构造函数,编译器将不再提供默认构造函数Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024,5,5);//代码执行正确Date d2;//error!!return 0;
}

上面代码中由于用户自定义了构造函数,则编译器不再提供无参的默认构造函数。此时创建d2时将会报错,因为此时并没有默认构造函数。

  1. 在用户不是实现构造函数时,编译器实现的默认构造函数的作用:对于内置类型(C++语言提供的默认类型,如int/char等),不会对它们做任何处理;对于自定义类型(使用class/struct/union等定义的类型),会调用它们的默认构造函数(也称为无参构造函数)。
#include <iostream>
using namespace std;class Time
{
public:Time(){cout << "Time()正在被调用" << endl;_hour = _minute = _second = 0;}
private:int _hour;int _minute;int _second;
};class Date
{
public:void Print(){cout << _year << "/" << _month << "/" << _day << endl;cout << _t._hour << "/" << _t._minute << "/" << _t._second << endl;}
private://基本类型(内置类型)int _year;int _month;int _day;//自定义类型Time _t;
};int main()
{Date d;d.Print();return 0;
}

在这里插入图片描述

上面代码执行结果如上图所示。可以看到Date提供的默认构造函数对C++内置类型没有做任何操作,所以它们都是一些随机值;对于自定义类型,Date会调用它们的默认构造函数。

★ps:C++11中为了解决默认构造函数不会初始化内置类型的问题,打了如下补丁:内置类型的成员变量在声明时可以给出默认值。给出默认值后,类在创建时会给内置类型的成员变量赋予默认值

#include <iostream>
using namespace std;class Time
{
public:Time(){cout << "Time()正在被调用" << endl;_hour = _minute = _second = 0;}
private:int _hour;int _minute;int _second;
};class Date
{
public:void Print(){cout << _year << "/" << _month << "/" << _day << endl;cout << _t._hour << "/" << _t._minute << "/" << _t._second << endl;}
private://基本类型(内置类型)int _year = 0;int _month = 0;int _day = 0;//自定义类型Time _t;
};int main()
{Date d;d.Print();return 0;
}

在这里插入图片描述
7. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认函数只能有一个。
★ps:我们不能在同一个类中同时提供无参构造函数和全缺省的构造函数。

下面代码中由于同时提供了无参构造和全缺省的构造函数,在main定义调用默认构造的类对象时,编译器无法确定调用无参构造还是全缺省的构造函数。(程序存在二义性)

#include <iostream>
using namespace std;class Date
{
public:Date(){_year = 2024;_month = 6;_day = 1;}Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;Time _t;
};int main()
{Date d1;return 0;
}

析构函数

概念

上面我们介绍了用于对象创建时的成员函数,那有没有用于对象销毁的成员函数呢?

析构函数:与构造函数功能相反,析构函数用于清理对象的存储空。但析构函数不是完成对对象本身的销毁,它主要用于销毁对象申请的堆空间,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

特性

析构函数是特殊的成员函数,其特征如下:

  1. 析构函数名是在类名前加上字符 ~
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构
    函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

析构函数主要用于清理对象申请的堆空间,对于局部变量的释放工作,由编译器完成。下面代码中演示了析构函数的定义和调用情况↓↓↓

#include <iostream>
using namespace std;class Stack
{
public:Stack(int n = 5){_arr = (int*)malloc(sizeof(int) * n);_size = 00;_capacity = 0;}//析构函数~Stack(){cout << "~Stack()被调用" << endl;free(_arr);_arr = nullptr;_size = _capacity = 0;}
private:int* _arr;int _size;int _capacity;
};int main()
{Stack s;//在s的声明周期结束时,s的析构函数将被自动调用return 0;
}

在这里插入图片描述
5. 关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认析构函数,对自定类型成员变量调用它的析构函数。

#include <iostream>
using namespace std;class Time
{
public:~Time(){cout << "~Time()被调用" << endl;}
private:int _hour;int _minute;int _second;
};class Date
{
public:
private://基本类型(内置类型)int _year = 0;int _month = 0;int _day = 0;//自定义类型Time _t;
};int main()
{Date d;//在d生命周期结束后,将会调用析构函数,d的默认析构函数会调用自定义类型的析构函数return 0;
}

在这里插入图片描述
6. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如上面定义的Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如上面定义的Stack类。

拷贝构造函数

概念

在程序中,优势需要对每个对象做备份。那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

特性

拷贝构造函数也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。
#include <iostream>
using namespace std;class Date
{
public:Date(int year = 0, int month = 0, int day = 0){_year = year;_month = month;_day = day;}//拷贝构造Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year = 0;int _month = 0;int _day = 0;
};int main()
{Date d1(2024,6,1);Date d2(d1);d1.Print();d2.Print();return 0;
}

在这里插入图片描述

  1. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用

如果使用值传递调用拷贝函数,在给拷贝构造函数传参时也是一次拷贝,这次拷贝需要调用拷贝构造函数;调用拷贝构造又是值传递,拷贝构造函数传参时也是一次拷贝,这次拷贝需要调用拷贝构造函数…(引发无穷递归调用)

在这里插入图片描述
3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。(被拷贝对象的各个成员变量存什么值,新创建的对象的各个成员变量也存什么值)。

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的

#include <iostream>
using namespace std;class Time
{
public:Time(){}Time(const Time& t){cout << "Time(const Time& t)被调用" << endl;}
private:int _hour;int _minute;int _second;
};class Date
{
public:
private://基本类型(内置类型)int _year = 0;int _month = 0;int _day = 0;//自定义类型Time _t;
};int main()
{Date d1;Date d2(d1);return 0;
}

在这里插入图片描述
★ps:编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

#include <iostream>
using namespace std;class Stack
{
public:Stack(int n = 5){_arr = (int*)malloc(sizeof(int) * n);_size = 00;_capacity = 0;}//析构函数~Stack(){cout << "~Stack()被调用" << endl;free(_arr);_arr = nullptr;_size = _capacity = 0;}
private:int* _arr;int _size;int _capacity;
};int main()
{Stack s1;Stack s2(s1);return 0;
}

在这里插入图片描述
为什么上面的代码会引发错误呢?

由于编译器自动生成的构造函数是按字节挨个拷贝的,导致s2中_arr和s1的_arr指向同一块内存空间。当s2生命周期结束后会调用了析构函数将这片内存空间释放,s1在生命周期结束也会释放这片空间。一块内存空间被重复释放从而导致错误。这种现象称为浅拷贝。
在这里插入图片描述
因此,如果类中有向堆申请空间,需要我们自己重新编写拷贝构造函数。在新创建的对象的构造函数中开辟一片新的内存空间,将待拷贝对象堆中的数据挨个拷贝进来。这种重写拷贝的行为称为深拷贝

#include <iostream>
#include <cstring>
using namespace std;class Stack
{
public:Stack(int n = 5){_arr = (int*)malloc(sizeof(int) * n);_size = 00;_capacity = 0;}//重写拷贝构造函数Stack(const Stack& s){_arr = (int*)malloc(sizeof(int) * s._capacity);memcpy(_arr, s._arr, sizeof(int) * s._capacity);_size = s._size;_capacitu = s._capacity;}//析构函数~Stack(){cout << "~Stack()被调用" << endl;free(_arr);_arr = nullptr;_size = _capacity = 0;}
private:int* _arr;int _size;int _capacity;
};int main()
{Stack s1;Stack s2(s1);return 0;
}

★ps:注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

5.拷贝构造函数典型调用场景:
①使用已存在对象创建新对象
②函数参数类型为类类型对象
③函数返回值类型为类类型对象

#include <iostream>
using namespace std;class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}Date(const Date& d){cout << "拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}
private:int _year = 0;int _month = 0;int _day = 0;
};Date func(Date d)
{return d;
}int main()
{Date d1;Date d2 = func(d1);return 0;
}

上面代码中一共调用了3次构造函数,如下图所示。但由于第2次和第3次拷贝连续发生,可能会被编译器优化成一次。(编译器具体如何优化,随编译器的不同而不同)
在这里插入图片描述
★ps:为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用尽量使用引用。

赋值运算符重载

运算符重载

如果我们想实现两个日期类的比较,我们可以使用一个isequal函数来实现↓↓↓

bool isequal(Date& d1, Date& d2)
{return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
}
int main()
{Date d1(2023, 1, 1);Date d2(2024, 5, 1);cout << isequal(d1, d2) << endl;
}

虽然上面的代码能够实现我们需要的功能。但我们在比较两个内置类型是否相等时,都会使用==运算符。为了让自定义类型能和内置类型一样使用常用的运算符,C++引入运算符重载。

运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名字为:operator+需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)

我们来看一下运算符重载如何实现两个日期类对象的比较↓↓↓

#include <iostream>
using namespace std;
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}//运算符重载//返回值+operator+需要重载的运算符+参数列表bool operator==(const Date& d){return _year == d._year && _month == d._month && _day == d._day;}
private:int _year = 0;int _month = 0;int _day = 0;
};int main()
{Date d1(2023,1,1);Date d2(2024,5,1);cout << (d1 == d2) << endl;return 0;
}

注意:
①不能重载C++中不存在的运算符:比如operator@
②重载操作符必须有一个类类型参数
③内置类型(如char、int等)的运算符不能被重载
④作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this指针
.*::sizeof?:. 注意以上5个运算符不能重载。

★ps:由于运算符重载的左操作数必须用this指针传入,故运算符重载函数只能在类内实现,而不能定义在类外。在类外定义如下下代码是不能编译通过的,因为编译器不会给它传入隐藏的this指针。

bool operator==(const Date& d2)
{return _year == d2._year && _month == d2._month && _day == d2._day;
}

赋值运算符重载

1.赋值运算符重载格式↓↓↓

参数类型:const T&,传递引用可以提高传参效率,const可以防止在重载函数中修改传入的对象
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
返回*this :因为要满足连续赋值,所以要返回自身(用于将自身给下一个对象赋值)
注意:函数体内需要检测是否自己给自己赋值

#include <iostream>
using namespace std;
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}//赋值运算符重载Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year = 0;int _month = 0;int _day = 0;
};int main()
{Date d1(2023,1,1);Date d2 = d1;d1.Print();d2.Print();return 0;
}

在这里插入图片描述
2. 赋值运算符只能重载成类的成员函数不能重载成全局函数

★ps:原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

  1. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。

既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

#include <iostream>
using namespace std;class Stack
{
public:Stack(int n = 5){_arr = (int*)malloc(sizeof(int) * n);_size = 00;_capacity = 0;}~Stack(){cout << "~Stack()被调用" << endl;free(_arr);_arr = nullptr;_size = _capacity = 0;}
private:int* _arr;int _size;int _capacity;
};int main()
{Stack s1;Stack s2 = s1;return 0;
}

在这里插入图片描述
这里发生的错误和拷贝构造函数一样。由于编译器自动形成operator=函数是按直接进行拷贝的,导致两个Stack指向同一片内存空间,该内存空间被重复释放导致出错。因此,上面的代码应该修改成这样↓↓↓

#include <iostream>
#include <cstring>
using namespace std;class Stack
{
public:Stack(int n = 5){_arr = (int*)malloc(sizeof(int) * n);_size = 00;_capacity = 0;}Stack& operator=(const Stack& s){_arr = (int*)malloc(sizeof(int) * s._capacity);memcpy(_arr, s._arr, size(int) * s._size);_size = s._size;_capacity = s._capacity;}~Stack(){cout << "~Stack()被调用" << endl;free(_arr);_arr = nullptr;_size = _capacity = 0;}
private:int* _arr;int _size;int _capacity;
};int main()
{Stack s1;Stack s2 = s1;return 0;
}

如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。

★ps:注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

#include <iostream>
using namespace std;class Time
{
public:Time(){}Time& operator=(const Time& t){cout << "Time& operator=(const Time& t)" << endl;_hour = t._hour;_minute = t._minute;_second = t._second;return *this;}
private:int _hour;int _minute;int _second;
};class Date
{
public:
private://基本类型(内置类型)int _year = 0;int _month = 0;int _day = 0;//自定义类型Time _t;
};int main()
{Date d1;Date d2;d2 = d1;return 0;
}

在这里插入图片描述
★ps:如下代码是拷贝构造而不是赋值。因为此时d2并未构造,编译器会将Date d2 = d1;转化成Date d2 = Date(d1);完成拷贝构造。

void test()
{Date d1(2024,5,1);Date d2 = d1;
}

前置++与后置++

通过上面的了解,我们可以理解下面的代码↓↓↓

class NumSet
{
public:Numset(int num = 0){_num = num;}NumSet& operator++(){++_num;return *this;}
private:int _num;
}

上面代码实现的是前置++。对于重载++运算符,如果重载函数的参数列表没有参数,则是实现的是前置++。完成前置++要将自身返回给调用处(也就是++后的结果)。

那如何实现后置++呢?C++中规定,如果要实现后置++,要在对应函数的参数列表添加一个int类型的占位参数。(这里没有为什么,这只是C++的规定)

class NumSet
{
public:Numset(int num = 0){_num = num;}NumSet& operator++(int){Numset tmp = Numset(*this);++_num;return tmp;}
private:int _num;
}

如果我们在调用后置++时,编译器默认会给operator++函数传递一个整型数,从而调用后置++。我们可以使用NumSet n; n.operator++(0);显示调用后置++。

后置–和前置–与上面的代码类似,这里不再介绍。

const成员

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
在这里插入图片描述
下面有几个问题,这里一起讨论一下:

  1. const对象可以调用非const成员函数吗?
    解答:const对象的不能修改对象的成员变量,但非const成员函数能修改成员变量。这答案很明显,const对象不能调用非const成员函数,因为这属于权限放大。
  2. 非const对象可以调用const成员函数吗?
    解答:非const对象的成员变量是可以修改的,const成员函数不可以修改成员函数。这里属于权限的缩小,因此非const对象可以调用const成员函数。
  3. const成员函数内可以调用其它的非const成员函数吗?
    解答:这属于权限放大,故const成员函数内不可以调用其它的非const成员函数
  4. . 非const成员函数内可以调用其它的const成员函数吗?
    解答:这属于权限缩小,故非const成员函数内可以调用其它的const成员函数。

取地址及const取地址操作符重载

这两个操作符的重载与上面介绍的其他运算符重载类似,这里不做赘述,直接给出代码示例↓↓↓

class Date
{
public :Date* operator&(){return this;}const Date* operator&() const{return this;}
private:int _year = 0;int _month = 0;int _day = 0;
};

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载。

🎈欢迎进入浅尝C++专栏,查看更多文章。
如果上述内容有任何问题,欢迎在下方留言区指正b( ̄▽ ̄)d

这篇关于【浅尝C++】类和对象第二弹=>类的6个默认成员函数/运算符重载详谈的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/847157

相关文章

Kotlin 作用域函数apply、let、run、with、also使用指南

《Kotlin作用域函数apply、let、run、with、also使用指南》在Kotlin开发中,作用域函数(ScopeFunctions)是一组能让代码更简洁、更函数式的高阶函数,本文将... 目录一、引言:为什么需要作用域函数?二、作用域函China编程数详解1. apply:对象配置的 “流式构建器”最

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

PyCharm如何设置新建文件默认为LF换行符

《PyCharm如何设置新建文件默认为LF换行符》:本文主要介绍PyCharm如何设置新建文件默认为LF换行符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录PyCharm设置新建文件默认为LF换行符设置换行符修改换行符总结PyCharm设置新建文件默认为LF

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.