笔记②:牛客校招冲刺集训营---C++工程师(面向对象(友元、运算符重载、继承、多态) -- 内存管理 -- 名称空间、模板(类模板/函数模板) -- STL)

0618

C++工程师

第5章 高频考点与真题精讲

5.1 指针 & 5.2 函数

5.3 面向对象(和5.4、5.5共三次直播课)

5.3.1 - 5.3.11

笔记①:牛客校招冲刺集训营—C++工程师

5.3.12-14 友元

友元分为三种:

  • 友元全局函数
  • 友元成员函数
  • 友元类

友元的目的就是让一个 函数或者类 能够访问另一个类中私有成员,关键字是 friend。重载<<运算符时,会用到友元。

友元全局函数

一个全局函数想访问一个类中的私有成员变量,那么就把这个全局函数设置为这个类的友元(friend),就可以访问了。
在这里插入图片描述
在这里插入图片描述

友元类

一个好朋友类想访问Building类中的私有成员变量,那么就把好朋友类设置为Building类的友元(friend),就可以访问了。
在这里插入图片描述
在这里插入图片描述

友元成员函数

好朋友类的成员函数visit()访问另一类的对象的私有成员变量:
在这里插入图片描述
成员函数visit()在类外实现:
在这里插入图片描述
Building类中把GoodFriend类的成员函数visit()设置为友元,就可以访问自己的m_BedRoom属性;
但GoodFriend类的成员函数visit1()没被设置为友元,所以还是无法访问到自己的m_BedRoom属性。

在这里插入图片描述

友元的注意事项

友元关系:
1.不能被继承; 2.是单向的; 3.不具有传递性。
在这里插入图片描述

5.3.15-23 运算符重载 -->静态多态

运算符 + = == != ++ () << 重载

C++笔记10:运算符重载
概念:
对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
例如:加号运算符重载的作用就是实现两个自定义数据类型(类)相加的运算

实现的方式有两种:

  • 利用成员函数重载
  • 利用全局函数重载

C++笔记10:运算符重载中实现了:

  • 加号运算符(+)重载
  • 左移运算符(<<)重载
    改进
  • 递增运算符(++)重载(前置++ 和 后置++)
  • 赋值运算符(=)重载
    如果类的成员变量在堆区,做赋值操作时就会出现深拷贝与浅拷贝问题。
  • 关系运算符重载(==!=
  • 函数调用运算符()重载—仿函数(在STL中用的比较多)
运算符 成员函数实现 全局函数实现 备注
加号运算符(+)重载 Students operator+(const Students& stu){} friend Students operator+(const Students& stu1, const Students& stu2){}
左移运算符(<<)重载 friend ostream& operator<<(ostream& cout, const Students& stu){}//可以实现连续cout输出
递增运算符(++)重载 前置++:Students& operator++(){}
后置++:Students operator++(int){}//这个int是为了和前置++形成重载,以通过编译,int本身没啥用
前置++:friend Students& operator++(Students& stu){}
后置++:friend Students operator++(Students& stu,int){}//这个int是为了和前置++形成重载,以通过编译,int本身没啥用
关系运算符(==!=)重载 bool operator==(Students& stu) {} friend bool operator==(const Students& stu1, const Students& stu2){}
赋值运算符(=)重载 void operator=(const Person& p){}
升级版:Person& operator=(const Person& p){}//可以实现连续赋值
函数调用运算符()重载 也叫仿函数

在这里插入图片描述

(以上是笔记中复制来的内容)

☆☆☆指针运算符重载(* 和 ->)(写个智能指针类)

视频课01:32:10开始)
指针的操作就是解引用*和箭头->,所以就是重载这两个运算符。

示例:

#include<iostream>
using namespace std;

class Person{
   
public:
    Person(int age){
   
        cout << "Person的构造函数" << endl;
        m_Age = age;
    }
    //输出成员信息:
    void showAge(){
   
        cout << "m_Age = " << this->m_Age << endl;
    }
    ~Person(){
   
        cout << "Person的析构函数" << endl;
    }
private:
    int m_Age;
};

//智能指针类:
class SmartPointer{
   
public:
    //重载箭头运算符->
    Person* operator->(){
   
        return this->m_Person;
    }
    //重载解引用运算符*
    Person& operator*(){
   
        return *m_Person;
    }
    SmartPointer(Person* p){
   
        cout << "SmartPointer的构造函数" << endl;
        m_Person = p;
    }
    ~SmartPointer(){
   
        cout << "SmartPointer析构函数" << endl;
        if(this->m_Person != nullptr){
   
            delete this->m_Person;
            this->m_Person == nullptr;
        }
    }
//private:
    Person* m_Person;//内部维护的Person的指针
};

int main(){
   
    Person* p = new Person(30);
    p->showAge();
    (*p).showAge();
    //正常应该执行下面这行,如果忘了就会造成内存泄漏,所以就用下面的智能指针类
    //delete p;
     
    cout << "=================================" << endl;
    //智能指针类就是把p替换成了sp,并且在其析构函数中将new的内容delete掉,这样就解决了可能造成的内存泄漏问题
    SmartPointer sp(p);
    sp->showAge();//相当于sp.operator->()->showAge(); 其中sp.operator->()就相当于p
    sp.operator->()->showAge();
    //编译器会把sp.operator->()->showAge()优化成sp->showAge();

    (*sp).showAge();//相当于sp.operator*().showAge();其中sp.operator*()相当于*p
    sp.operator*().showAge();
    //编译器会把sp.operator*().showAge()优化成(*sp).showAge();

    return 0;

}

编译运行:

Person的构造函数
m_Age = 30
m_Age = 30
=================================
SmartPointer的构造函数
m_Age = 30
m_Age = 30
m_Age = 30
m_Age = 30
SmartPointer析构函数
Person的析构函数
运算符重载的应用:封装字符串类

视频课:点这里

5.3.24 类的自动类型转换和强制类型转换(关键字explicit

explicit修饰的构造函数不能用于自动类型转换(隐式类型转换)。

示例:

#include <iostream>
using namespace std;

class MyString {
   
public:
	// 被explicit修饰的构造函数不能用于自动类型转换(隐式类型转换)
	explicit MyString(int len) {
   
		cout << "MyString有参构造MyString(int len)..." << endl;
	}

	//explicit 
    MyString(const char* str) {
   
		cout << "MyString有参构造MyString(const char* str)..." << endl;
	}

	// 转换函数:转换成double
	operator double() {
   
		// 业务逻辑
		return 20.1;
	}

};

// 类的自动类型转换和强制类型转换
/*
	如果我们想让类对象转换成基本类型的数据,我们需要在类中添加转换函数
	1.转换函数必须是类方法
	2.转换函数不能指定返回类型
	3.转换函数不能有参数
*/
int main() {
   

	// 基本内置数据类型的自动类型转换和强制类型转换
	long count = 8;
	double time = 10;
	int size = 3.14;
	cout << count << endl;  //8
	cout << time << endl;   //10
	cout << size << endl;   //3

	double num = 20.3;
	cout << num << endl;    //20.3
	// 强制转换成int类型的数据
	int num1 = (int)num;    
	int num2 = int(num);
	cout << num1 << endl;   //20
	cout << num2 << endl;   //20

	MyString str = "hello";	//
    // MyString str = MyString("hello");

	// MyString str1 = 10;	//不能通过隐式类型转换创建对象了
	MyString str1 = MyString(10);

	// 类的强制类型转换
	double d = str1;
	cout << d << endl;      //20.1

	double d1 = double(str);
	double d2 = (double)str;
	cout << d1 << endl;     //20.1
	cout << d2 << endl;     //20.1

	return 0;
}

结果:

8
10
3
20.3
20
20
MyString有参构造MyString(const char* str)...
MyString有参构造MyString(int len)...
20.1
20.1
20.1

5.3.25-34 继承

继承的概念、好处、弊端

继承是面向对象的一大特征。

继承好处:

  • 提高代码的复用性;
  • 提高代码的维护性(方便维护);
  • 让类与类之间产生了关系,是(动态)多态的前提。

继承的弊端:

  • 类的耦合性增加了

开发的原则是:高内聚,低耦合
内聚:自己完成一件事的能力;
耦合:类和类之间的关系。

继承的基本语法

继承的语法:

class 子类:继承方式 父类{
    
...
};

例如:
class dogs: public Animals {
    
...
};

继承方式分为public,protected,private,即公共继承,保护继承,私有继承

注意:
如果不写继承方式,默认是私有继承

protected访问权限

三种权限:

  • public: 公共的访问权限,被修饰的成员在类内和类外都能够被访问;
  • protected: 受保护的访问权限,如果没有继承关系,就和private的特点一样;
  • privated: 私有的访问权限,被修饰的成员只能在类内被访问,在类外不能够被访问;

在继承关系中,父类中的protected修饰的成员,子类中可以直接访问,但在类外的其他地方不能访问。

成员变量一般使用privated私有访问控制,不要使用protected受保护的访问控制;
成员方法如果想要让子类访问,但是不想让外界访问,就可以使用protected受保护的访问控制。

(下面的内容来自C++笔记3:C++核心编程中的4.6.2 继承方式
在这里插入图片描述

总结:
1.父类中的私有内容(private任何一种继承方式都访问不到,即无法被访问/被继承
2.公共继承:父类中的各访问权限不变
3.保护继承:父类中的各访问权限都变成protected保护权限
4.私有继承:父类中的各访问权限都变成private私有权限

无继承关系:

父类中的三个成员变量 父类类内访问 类外通过父类对象访问
public修饰的num1 可以访问 可以访问
protected修饰的num2 可以访问 不能访问
private修饰的num3 可以访问 不能访问

子类公共继承父类:class Zi : public Fu{ ... };

父类中的三个成员变量 子类中的三个成员变量 父类类内访问 子类类内访问 类外通过父类对象访问 类外通过子类对象访问
public修饰的num1 public修饰的num1 可以访问 可以访问 可以访问 可以访问
protected修饰的num2 protected修饰的num2 可以访问 (因为有继承关系,所以)
可以访问
不能访问 不能访问
private修饰的num3 private修饰的num3 可以访问 不能访问 不能访问 不能访问

子类保护继承父类:class Zi : protected Fu{ ... };

父类中的三个成员变量 子类中的三个成员变量 父类类内访问 子类类内访问 类外通过父类对象访问 类外通过子类对象访问
public修饰的num1 protected修饰的num1 可以访问 可以访问 可以访问 不能访问
protected修饰的num2 protected修饰的num2 可以访问 (因为有继承关系,所以)
可以访问
不能访问 不能访问
private修饰的num3 private修饰的num3 可以访问 不能访问 不能访问 不能访问

子类私有继承父类:class Zi : private Fu{ ... };

父类中的三个成员变量 子类中的三个成员变量 父类类内访问 子类类内访问 类外通过父类对象访问 类外通过子类对象访问
public修饰的num1 private修饰的num1 可以访问 可以访问 可以访问 不能访问
protected修饰的num2 private修饰的num2 可以访问 (因为有继承关系,所以)
可以访问
不能访问 不能访问
private修饰的num3 private修饰的num3 可以访问 不能访问 不能访问 不能访问

在这里插入图片描述

示例:

#include<iostream>
using namespace std;

class Fu{
   
public:
    int num1;
protected:
    int num2;
private:
    int num3;

public:
    void func(){
   
        num1 = 10;
        num2 = 20;
        num3 = 
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值