1. 引用
1.1. 什么是引用
作用:给变量起别名
语法:数据类型 &别名 = 原名;
本质:引用的本质是在 C++ 内部实现的一个常量指针。
特点:
- 引用必须初始化。
- 引用初始化后,不可以改变。
1.2. 引用使用方法
//引用的本质
int &b = a; //相当于 int* const b = &a;
------------------------------------------------------------------------------
//引用做函数参数
void swap(int &a, int &b){
int tmp = a;
a = b;
b = tmp;
}
int main() {
int a = 10;
int b = 20;
swap(a,b);
return 0;
}
------------------------------------------------------------------------------
//引用做返回值
int &test(){
staic int a = 10; //静态变量
return a;
}
int main(){
int &ret = test();
printf("ret[%d]\n", ret);
test() = 20; //函数作为左值
printf("ret[%d]\n", ret);
return 0;
}
------------------------------------------------------------------------------
2. 友元
2.1. 什么是友元
友元的目的就是让一个函数或者一个类,访问另一个类中私有成员。
友元的关键字为 friend。
2.2. 友元使用方法
//全局函数做友元
class building
{
friend void goodgay(building *building);
public:
char m_sittingroot[30]; //客厅
private:
char m_bedroom[30]; //卧室
}
void goodgay(building *building){
printf("bedroom = %s\n", building->m_bedroom);
}
int main(){
building building;
goodgay(&building);
return 0;
}
---------------------------------------------------------------------------
//类 做友元
class building;
class goodgay
{
public:
goodgay();
void visit(); //参观
building *building;
}
class building
{
frind class goodgay; //goodgay类可以访问building的私有成员
public:
building();
public:
char m_sittingroot[30]; //客厅
private:
char m_bedroom[30]; //卧室
}
building::building()
{
m_sittingroot = "客厅";
m_bedroom = "卧室";
}
goodgay::goodgay() {
building = new building();
}
void goodgay::visit()
{
printf("bedroom = %s\n", building->m_bedroom);
}
int main(){
goodgay gg;
gg.visit();
}
---------------------------------------------------------------------------
//成员函数做 友元
class goodgay
{
public:
goodgay();
void visit(); //让visit函数可以访问building中的私有成员
void visit2(); //让visit函数不可以访问building中的私有成员
building *building;
}
class building
{
friend void goodgay::visit(); //告诉编译器goodgay类下的成员函数是友元函数
public:
building();
public:
char m_sittingroot[30]; //客厅
private:
char m_bedroom[30]; //卧室
}
goodgay::goodgay() {
building = new building();
}
building::building()
{
m_sittingroot = "客厅";
m_bedroom = "卧室";
}
void goodgay::visit()
{
printf("bedroom = %s\n", building->m_bedroom);
}
int main(){
goodgay gg;
gg.visit();
}
3. 封装
3.1. 封装的作用
- 尽量使代码或者功能独立 (保证代码和功能独立性)。
- 封装,可以达到,对外提供接口,屏蔽数据,对内开放数据。
- c++的封装:class 封装的本质,在于将数据和行为,绑定在一起然后通过对象来完成操作。
3.2. 封装的示例
1. public 公共权限
2. protected 保护权限:子类可以使用
3. private 私有权限:子类不可使用
---------------------------------------------------------------------
class student{
//访问权限
public:
//属性
char m_name[50];
int m_id;
//行为
void show_student() {
printf("name[%s] id[%d]", m_name, m_id);
}
protected:
char m_car[50];
private:
char m_password[10];
};
int main(){
//实例化对象
student s1;
strcyp(s1.m_name, "zhao");
s1.id = 1;
s1. show_student();
return 0;
}
4. 继承
4.1. 什么是继承
继承是c++语言一个重要的机制,该机制自动地为一个类提供来自另一个类的操作和数据结构,这使得程序员只需在新类中定义已有的类中没有的成分来建立一个新类。
继承关系可分为3个级别:
- public 公共权限
- protected 保护权限:子类可以使用
- private 私有权限:子类不可使用
4.2. 继承的示例
// 基类 Animal
class Animal {
public:
void eat() {
std::cout << "Animal is eating\n";
}
void sleep() {
std::cout << "Animal is sleeping\n";
}
};
// 派生类 Dog,单继承自 Animal
class Dog : public Animal {
public:
void bark() {
std::cout << "Dog is barking\n";
}
};
int main() {
// 创建 Dog 对象
Dog dog;
dog.eat(); // 输出:Animal is eating
dog.sleep(); // 输出:Animal is sleeping
dog.bark(); // 输出:Dog is barking
return 0;
}
4.3. 虚继承
派生类可以重写基类的函数。
#include <iostream>
// 基类 Animal
class Animal {
public:
void eat() {
std::cout << "Animal is eating\n";
}
void sleep() {
std::cout << "Animal is sleeping\n";
}
};
// 派生类 Bird,虚继承自 Animal
class Bird : virtual public Animal {
public:
// 重写 eat 方法
void eat() {
std::cout << "Bird is eating seeds\n";
}
// 重写 sleep 方法
void sleep() {
std::cout << "Bird is sleeping on a branch\n";
}
void chirp() {
std::cout << "Bird is chirping\n";
}
};
int main() {
// 创建 Bird 对象
Bird bird;
bird.eat(); // 输出:Bird is eating seeds
bird.sleep(); // 输出:Bird is sleeping on a branch
bird.chirp(); // 输出:Bird is chirping
return 0;
}
4.4. 纯虚函数
基类中只需要声明纯虚函数,不需要实现。子类必须实现该函数。
#include <iostream>
// 基类 Animal
class Animal {
public:
virtual void eat() = 0;
virtual void sleep() = 0;
};
// 派生类 Bird,虚继承自 Animal
class Bird : public Animal {
public:
// 重写 eat 方法
void eat() {
std::cout << "Bird is eating seeds\n";
}
// 重写 sleep 方法
void sleep() {
std::cout << "Bird is sleeping on a branch\n";
}
void chirp() {
std::cout << "Bird is chirping\n";
}
};
int main() {
// 创建 Bird 对象
Bird bird;
bird.eat(); // 输出:Bird is eating seeds
bird.sleep(); // 输出:Bird is sleeping on a branch
bird.chirp(); // 输出:Bird is chirping
return 0;
}
5. 多态
5.1. 什么是多态
多态的实现依赖于虚函数(virtual function)和动态绑定(dynamic binding)的机制。在 C++ 中,将基类中的方法声明为虚函数,子类可以选择性地重写这些虚函数。当通过基类的指针或引用调用虚函数时,程序在运行时会根据对象的实际类型动态地确定调用哪个版本的函数,这就是动态绑定。
优点:
代码重用:通过继承和多态,可以重用基类中的方法和行为,减少代码冗余。
可扩展性:通过添加新的子类,可以扩展系统的功能,而不需要修改现有的代码。
灵活性:同一个方法调用可以在不同对象上产生不同的行为,提高了代码的灵活性和可适应性。
简化接口:多态性使得程序可以通过统一的接口调用不同对象的方法,简化了接口设计。
5.2. 多态示例
//多态实现
//抽象计算器类
//多态优点:代码组织结构清晰,可读性强,利于前期和后期的扩展以及维护
class AbstractCalculator
{
public :
virtual int getResult()
{
return 0;
}
int m_Num1;
int m_Num2;
};
//加法计算器
class AddCalculator :public AbstractCalculator
{
public:
int getResult()
{
return m_Num1 + m_Num2;
}
};
//减法计算器
class SubCalculator :public AbstractCalculator
{
public:
int getResult()
{
return m_Num1 - m_Num2;
}
};
//乘法计算器
class MulCalculator :public AbstractCalculator
{
public:
int getResult()
{
return m_Num1 * m_Num2;
}
};
int main() {
//创建加法计算器
AbstractCalculator *abc = new AddCalculator;
abc->m_Num1 = 10;
abc->m_Num2 = 10;
cout << abc->m_Num1 << " + " << abc->m_Num2 << " = " << abc->getResult() << endl;
delete abc; //用完了记得销毁
//创建减法计算器
abc = new SubCalculator;
abc->m_Num1 = 10;
abc->m_Num2 = 10;
cout << abc->m_Num1 << " - " << abc->m_Num2 << " = " << abc->getResult() << endl;
delete abc;
//创建乘法计算器
abc = new MulCalculator;
abc->m_Num1 = 10;
abc->m_Num2 = 10;
cout << abc->m_Num1 << " * " << abc->m_Num2 << " = " << abc->getResult() << endl;
delete abc;
return 0;
5.3. 虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
- 可以解决父类指针释放子类对象
- 都需要有具体的函数实现
虚析构和纯虚析构区别:
- 如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名() = 0;
类名::~类名(){}
class Animal {
public:
Animal()
{
cout << "Animal 构造函数调用!" << endl;
}
virtual void Speak() = 0;
//析构函数加上virtual关键字,变成虚析构函数
//virtual ~Animal()
//{
// cout << "Animal虚析构函数调用!" << endl;
//}
virtual ~Animal() = 0;
};
Animal::~Animal()
{
cout << "Animal 纯虚析构函数调用!" << endl;
}
//和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。
class Cat : public Animal {
public:
Cat(string name)
{
cout << "Cat构造函数调用!" << endl;
m_Name = new string(name);
}
virtual void Speak()
{
cout << *m_Name << "小猫在说话!" << endl;
}
~Cat()
{
cout << "Cat析构函数调用!" << endl;
if (this->m_Name != NULL) {
delete m_Name;
m_Name = NULL;
}
}
public:
string *m_Name;
};
void test01()
{
Animal *animal = new Cat("Tom");
animal->Speak();
//通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏
//怎么解决?给基类增加一个虚析构函数
//虚析构函数就是用来解决通过父类指针释放子类对象
delete animal;
}
int main() {
test01();
system("pause");
return 0;
}
6. 运算符重载
6.1. 运算符重载的作用
对已有的运算符重新定义,赋予其另一种功能,以适应不同的数据类型。
6.2. + 运算符重载
#include <iostream>
class Counter {
private:
int count;
public:
Counter(int c = 0) : count(c) {}
// 重载加法运算符 +
Counter operator+(const Counter& other) {
Counter result;
result.count = this->count + other.count;
return result;
}
// 获取计数器当前值
int getCount() const {
return count;
}
};
int main() {
Counter c1(5); // 创建计数器对象 c1,初始值为 5
Counter c2(3); // 创建计数器对象 c2,初始值为 3
Counter c3 = c1 + c2; // 使用重载的加法运算符将 c1 和 c2 相加,结果赋值给 c3
std::cout << "c1 count: " << c1.getCount() << std::endl; // 输出 c1 的计数器值
std::cout << "c2 count: " << c2.getCount() << std::endl; // 输出 c2 的计数器值
std::cout << "c3 count: " << c3.getCount() << std::endl; // 输出 c3 的计数器值
return 0;
}