Linux 学习记录42(C++篇)
本文目录
- Linux 学习记录42(C++篇)
- 一、class 类
- 1. 类中的this指针
- (1. this指针的格式
- (2. 使用this指针
- 2. 类中特殊的成员函数
- (1. 构造函数
- >1 格式/定义
- >2 调用构造函数的时机
- >3 构造函数的初始化列表
- (2. 析构函数
- >1 功能/格式
- >2 析构函数的调用时机
- >3 需要显性调用析构函数情况
- >4 定义和使用
- (3. 拷贝构造函数
- >1 格式
- >2 调用时机
- >3 定义和使用
- >4. 深/浅拷贝
- (4. 拷贝赋值函数
- >1 格式
- >2 定义
- >3. 深/浅拷贝
- 3. 匿名对象
- (1.使用场景
- (2. 定义
- 4. 类的大小
- 思维导图
- 练习
@
一、class 类
1. 类中的this指针
类内默认提供给非静态成员函数的this指针,指针指向类对象本身,哪个对象调用成员函数,this就指向哪个对象
(1. this指针的格式
格式:类名* const this; //不能改变this的指向
(2. 使用this指针
1. 如果函数的形参和成员属性同名时,需要使用this指针解决
2. 拷贝赋值函数中,需要返回自身的引用,也需要使用this指针解决
class Rectangle
{
private://私有的成员属性/方法
int a;
public://公有的成员属性/方法
void set_a(int a)
{
"在这里函数的参数a和类中的a变量名重复所以无法确定到底是那个变量,所以需要用到this指针"
a = a;
}
protected://受保护的成员属性/方法
};
============================修改后如下================================
class Rectangle
{
private://私有的成员属性/方法
int a;
public://公有的成员属性/方法
void set_a(int a)
{
this->a = a;
}
protected://受保护的成员属性/方法
};
2. 类中特殊的成员函数
如果程序员不手动定义,系统会默认提供的函数,系统默认提供的是无参构造
1. 构造函数 (常用)
2. 析构函数 (常用)
3. 拷贝构造函数 (常用)
4. 拷贝赋值函数 (常用)
5. 取地址运算符重载函数
6. 常取地址运算符重载函数
7. C++11新增:移动构造函数
8. C++11新增:移动赋值函数
(1. 构造函数
使用情景:
1. 形参和成员属性同名
2. 类内有引用成员,必须使用初始化列表
3. 类内有const修饰的成员时,必须使用初始化列表
4. 类中包含其他类的的子对象时,其他类必须初始化时,需要使用初始化列表
>1 格式/定义
用于实例化类对象时,系统自动调用
功能:实例化类对象时,给类对象开辟空间和初始化
格式:类名(形参列表)
{
函数体;
}
例:
class test
{
private://私有的成员属性/方法
int a;
string b;
double c;
public://公有的成员属性/方法
/*有参构造和无参构造构成函数重载*/
test(int a,string b,double c)
{ //有参构造
this->a=a;
this->b=b;
this->c=c;
}
test()
{
//无参构造
}
protected://受保护的成员属性/方法
};
int main()
{
test p;
test p1(1,"abc",1.23);
return 0;
}
>2 调用构造函数的时机
构造函数一般是public权限的
- 在栈区
什么时候实例化对象,什么时候调用构造函数,系统默认调用
- 在堆区申请空间
什么时候用new申请空间,什么时候调用构造函数
>3 构造函数的初始化列表
构造函数提供了初始化列表的机制,在函数体外
格式: 类名(形参列表):成员属性1(参数1),成员属性2(参数2),成员属性3(参数3)...
{
函数体
}
例:
class test
{
private://私有的成员属性/方法
int a;
string b;
double c;
public://公有的成员属性/方法
/*有参构造和无参构造构成函数重载*/
test(int a,string b,double c):a(a),b(b),c(c)
{ //有参构造
/*函数体内的赋值
this->a=a;
this->b=b;
this->c=c;*/
}
protected://受保护的成员属性/方法
};
(2. 析构函数
>1 功能/格式
功能:在类对象消亡时回收类对象的空间
格式:
~类名()
{
函数体
}
>2 析构函数的调用时机
先构造的后析构
- 在栈区:
系统在对象消亡时,主动调用
- 在堆区:
使用delete关键字,释放空间时,主动调用析构函数
>3 需要显性调用析构函数情况
1. 系统会默认析构函数,在对象消亡时,主动调用,释放对象的空间
2. 析构函数不允许函数重载
3. 当类中有指针成员(指向堆区申请的空间)时,
>4 定义和使用
析构函数不支持重载
class test
{
private://私有的成员属性/方法
int a;
int* p;
string b;
double c;
public://公有的成员属性/方法
/*析构函数,会自动调用*/
~test()
{
/*释放指针指向的堆区空间地址*/
delete p;
p = nullptr;
}
protected://受保护的成员属性/方法
};
int main()
{
test* p = new test;
delete p;
return 0;
}
(3. 拷贝构造函数
使用已有类对象给新的类对象初始化时,会自动调用拷贝构造函数
>1 格式
类名(类名 &other)
{
函数体;
}
>2 调用时机
1. 使用已有的类对象给新的类对象初始化的时候,主动调用拷贝构造函数
2. 类对象作为函数的形参,主动调用拷贝构造函数
3. 类对象作为函数的返回值,主动调用拷贝构造函数
>3 定义和使用
class test
{
private://私有的成员属性/方法
int num;
string str;
public://公有的成员属性/方法
test()
{//无参构造函数
}
test(test &other)
{//拷贝构造函数
num = other.num;
str = other.str;
}
protected://受保护的成员属性/方法
};
int main()
{
test p1;//定义一个p1变量
test p2 = p1;//将p1拷贝一份给p2
return 0;
}
>4. 深/浅拷贝
如果类内有指针成员,涉及到深浅拷贝问题
- 浅拷贝
两个不同类对象的指针成员指向同一片空间,会造成一个类对象对其修改另一个类对象的值也会修改。
- 深拷贝
两个不同类对象的指针成员指向不同的空间,一个类对象的修改不会影响另一个类对象的值。
(4. 拷贝赋值函数
使用一个类对象给另一个类对象赋值时使用的,适于运算符重载
>1 格式
运算符重载的函数名:operator=
类名 &(const 类名 &引用)
{
函数体;
}
拷贝赋值函数会返回自身的引用
>2 定义
class test
{
private://私有的成员属性/方法
int num;
string str;
public://公有的成员属性/方法
test()
{
}
test &operator=(test &other)
{
num = other.num;
str = other.str;
return *this;//返回自身
}
protected://受保护的成员属性/方法
};
>3. 深/浅拷贝
拷贝赋值函数依然需要考虑深浅的问题,但是不需要再申请空间
要保证指针成员指向的地址在堆区才能delete释放
using namespace std;
class test
{
private://私有的成员属性/方法
int num;
int* p;
string str;
public://公有的成员属性/方法
test()
{
}
test(int a,int* b,string c):num(a),p(b),str(c)
{
}
test &operator=(test &other)
{
cout << "拷贝赋值" <<endl;
*p = *(other.p);//深拷贝
// p = other.p;//浅拷贝
num = other.num;
str = other.str;
return *this;//返回自身
}
void show(void)
{
cout << "p=" << p <<endl;
cout << "num=" << *p <<endl;
}
~test()
{
cout << "空间已释放" <<endl;
delete p;
p = nullptr;
}
protected://受保护的成员属性/方法
};
int main()
{
int num1 = 1;
int num2 = 2;
test buf1(num1,&num1,"buf1");
test buf2(num2,&num2,"buf2");
buf1.show();
buf2.show();
buf1 = buf2;
cout << "--------" <<endl;
buf1.show();
buf2.show();
return 0;
}
3. 匿名对象
匿名对象就是实例化对象时,没有实例名的对象,它的生命周期短,是一个临时值
(1.使用场景
使用场景:
1. 用作全局函数的临时传参
2. 使用临时对象给另一个类对象赋值
3. 临时使用成员方法
4. 类对象数组
(2. 定义
class test
{
private://私有的成员属性/方法
int num;
int* p;
string str;
public://公有的成员属性/方法
test(int a,int* b,string c):num(a),p(b),str(c)
{
}
protected://受保护的成员属性/方法
};
int main()
{
int num1 = 1;
test (num1,&num1,"buf1");//这里就实例化了一个匿名对象
return 0;
}
4. 类的大小
类的大小和结构体的大小是一致的,类中的函数在声明时也是不占用空间的
string类型 在64位占32个字节,32位占24字节(QT内)
string类型包含以下几个部分(QT中)
1. 指向字符数组的指针
2. 字符串的实际长度 size_t
3. 字符串能存储的最大长度
4. 系统能存储的最大长度
思维导图
练习
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cstdio>
using namespace std;
class Person
{
private:
int age;
int *p;
public:
//无参构造
Person():p(new int(89))
{
age = 18;
}
//有参构造
Person(int age,int num)
{
this->age = age;
this->p=new int(num);
}
//拷贝构造函数
Person(Person &other)
{
age = other.age;
p = new int (*(other.p));//深拷贝
// p = other.p;//浅拷贝
}
//拷贝赋值函数
Person operator=(Person &other)
{
age = other.age;
*p = *(other.p);//深拷贝
// p = other.p;//浅拷贝
return *this;
}
//析构函数
~Person()
{
delete p;
p = nullptr;
}
};
int main()
{
return 0;
}