CC++类与对象
# C/C++: 类与对象
C++面向对象的三大特性:封装、继承和多态
# 对象的初始化和清理
# 构造函数与析构函数
构造函数按参数分可分为无参构造和有参构造,按类型分可分为普通构造和拷贝构造;
class Person
{
public:
Person();
Person(int a);
// 拷贝构造
Person(const Person &p);
};
类的调用方法:
// 1. 调用默认构造函数
Person p1; // 注意不要加括号,否则会被认为是函数声明;
// 2. 显示调用
Person p2(10);
Person p3(p2);
// 匿名对象
Person(10); // 执行结束后系统立即回收销毁
// Person(p3);
// 注意不要利用拷贝构造函数初始化匿名对象,会被当做是 Person p3;但是后紧接一个成员函数则不会报错,如Person(p3).someMethod();
// 会产生 重定义 的错误
// 3. 隐式转换法
Person p4 = 10; // 相当于 Person p4 = Person(10);
Person p5 = p4;
# 拷贝构造函数的调用时机
- 使用一个已经创建完毕的对象来初始化一个新对象;
- 值传递的方式给函数参数传值;
- 以值的方式返回局部对象。
默认情况下,C++编译器至少给一个类添加如下四个函数:
- 默认构造函数(空)
- 默认析构函数(空)
- 默认拷贝构造函数(对属性进行值拷贝)
- 赋值运算符
operator=
对属性进行值拷贝
# 深拷贝与浅拷贝
在类的拷贝过程中属于浅拷贝,当类中有开辟在堆区的指针变量时,浅拷贝会将地址原封不动地复制过去,在析构函数中则会出现对同一块地址多次释放的风险,因而,需要自己实现拷贝构造函数以解决浅拷贝带来的问题。
Person(const Person &p)
{
m_Height = new int(*p.m_Height);
}
如果有属性在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题
有关于该问题,有几条前人总结的法则,可以作为参考:
- 如果定义了析构函数,那必须同时定义或删除拷贝构造函数和拷贝赋值函数;
- 如果一个类定义了拷贝构造函数,那么必须同时定义或删除拷贝赋值函数,负责出错,如果删除将导致低效;
- 如果类定义了移动构造函数,那么必须同时定义或删除移动赋值函数,否则出错,删除将导致低效;
- 如果类定义了拷贝构造函数或拷贝赋值函数,则最好同时定义移动构造函数或移动赋值函数,否则低效。
如何避免没有必要的拷贝?:使用常引用
const X& x
当然,对于原始数据类型,诸如int,float等,容器并不大,没有必要使用常引用。
如何避免不经意的隐式拷贝?:将拷贝构造函数声明为
explicit
,例如某函数void show(Pig pig);
,如果使用show(pig);
调用,则会编译错误,只能通过show(Pig{pig});
语法强制拷贝。
# 静态成员
静态成员分为:
静态成员变量
- 所有对象共享同一份数据
- 编译阶段分配内存
- 类内声明,类外初始化
class Person { Person(); ~Person(); public: static int m_A; }; // 类外初始化 int Person::m_A = 100;
由于共享数据,因此有以下访问数据的方式:
// 通过对象访问 Person p1; p1.m_A = 100; Person p2; p2.m_A = 200; // 通过类名访问 Person::m_A = 100;
静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量
# 空指针访问成员函数
空指针也可以调用成员函数,但当需要访问成员变量时则会报错,为了防止此类错误,可以添加如下语句:
void show()
{
if (this == NULL)
{
return;
}
// do something
}
# const修饰成员函数
常函数:
- 成员函数后加
const
后称为常函数 - 常函数内不可以修改成员属性
- 成员属性声明时加关键字
mutable
后,常函数中就可以修改
class Person
{
public:
void show() const
{
this->m_B = 100;
// this->m_A = 100;
}
int m_A;
mutable int m_B;
};
this指针的本质是指针常量,是对指针的修饰,当成员函数后加
const
后修饰的是指针的指向,即对指针和常量均修饰,所以不可以更改成员属性
常对象:
- 声明对象前加
const
称该对象为常对象; - 常对象只能调用常函数
- 常对象也可以修改加了关键字
mutable
的属性
void test()
{
const Person p;
// p.m_A = 100;
p.m_B = 100;
}
# 友元
友元的三种实现:
- 全局的函数做友元
- 类做友元
- 成员函数做友元
为了让全局函数friendFunc(Person* p)
访问类Person
中的私有成员,如下操作
class Person
{
friend void friendFunc(Person* p);
public:
int m_A;
private:
int m_B;
};
void friendFunc(Person* p)
{
std::cout << p.m_B;
}
同理类做友元只需在Person
类中添加代码
friend class GoodGuy;
成员函数做友元需要添加
friend void GoodGuy::visit();
编辑 (opens new window)
上次更新: 2023/08/15, 01:36:48