(黑马C++)L06 重载与继承

news2024/11/17 1:29:09

一、关系运算符重载

以重载等于号运算符为例:

#include<string>
#include <iostream>
using namespace std;

class Person {
public:
	Person(string Name, int age) {
		this->m_Name = Name;
		this->m_Age = age;
	}

public:
	string m_Name;
	int m_Age;
};

bool operator== (Person& p1, Person& p2) {
	if ((p1.m_Name == p2.m_Name) && (p1.m_Age == p2.m_Age)) {
		return true;
	}
	return false;
}

void test() {
	Person p1("小明", 10);
	Person p2("小强", 15);
	Person p3("小强", 15);
	if (p1 == p2) {
		cout << "p1和p2相等" << endl;
	}
	else {
		cout << "p1和p2不相等" << endl;
	}

	if (p2 == p3) {
		cout << "p2和p3相等" << endl;
	}
	else {
		cout << "p2和p3不相等" << endl;
	}
	
}

int main()
{
	test();
	system("pause");
	return 0;
}

二、函数调用运算符重载

函数调用运算符就是()。

#include <iostream>
#include <string>
using namespace std;

class MyPrint{
public:
	void operator() (string text) {
		cout << text << endl;
	}
};

void test() {
	MyPrint myPrint;
	myPrint("你好"); //仿函数
}

int main(int argc, char** argv)
{
	test();
	system("pause");
	return 0;
}

不要重载&&和||运算符,重载了&&和||符号后短路特性就会失效,按照符号的先后顺序进行运算。

符号重载的总结

  • =,[],()和->操作符只能通过成员函数进行重载
  • <<和>>只能通过全局函数配合友元函数进行重载
  • 不要重载&&和||操作符,因为重载后无法实现短路规则

三、强化训练-字符串封装

1.输出自定义的字符串;2.让用户能任意输入一个字符串。

//MyString.h
#pragma once //防止头文件重复编译
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class MyString {
	friend ostream& operator<< (ostream& cout, MyString& str);
	friend istream& operator>> (istream& cin, MyString& str);
public:
	//有参构造
	MyString(const char* str);
	//拷贝构造
	MyString(const MyString& str);
	//析构
	~MyString();

private:
	char* pString; //指向堆区的指针
	int m_Size; //字符串的大小
};


//MyString.cpp
#include "MyString.h"

//输出私有属性需要将其作为友元
ostream& operator<< (ostream& cout, MyString& str) {
	cout << str.pString;
	return cout;
}

//右移运算符的重载
istream& operator>> (istream& cin, MyString& str) {
	char buf[1024];
	//让用户输入的内容保存到str
	cin >> buf;
	if (str.pString != NULL) {
		delete[] str.pString;
		str.pString = NULL;
	}
	str.pString = new char[strlen(buf) + 1];
	strcpy(str.pString, buf);
	str.m_Size = strlen(buf);
	return cin;
}

MyString::MyString(const char* str)
{
	cout << "有参构造调用" << endl;
	this->pString = new char[strlen(str) + 1];
	strcpy(this->pString, str);
	this->m_Size = strlen(str);
}

MyString::MyString(const MyString& str)
{
	this->pString = new char[str.m_Size + 1];
	strcpy(this->pString, str.pString);
	this->m_Size = str.m_Size;
}

MyString::~MyString()
{
	cout << "析构函数调用" << endl;
	if (this->pString != NULL) {
		delete[] this->pString;
		this->pString = NULL;
	}
}


//字符串的封装.cpp
#include <string>
#include <iostream>
#include "MyString.h"
using namespace std;

//测试MyStrring
void test() {
	MyString str = "abc";
	cout << str << endl;
	cout << "请输入str新的内容:" << endl;
	cin >> str;
	cout << "您输入的str的内容为:" << str << endl;
}

int main()
{
	test();
	system("pause");
	return 0;
}


后续实现cin, cout, =, +, [], == 的重载功能。

四、继承的引出

两个类的成员函数及成员变量高度重复时,如果分别定义会出现很多重复代码,因此,引出继承,一个成员可直接继承另一个成员的属性。

继承的目的是为了减少代码冗余,被继承的类叫做基类(父类),继承的类叫做派生类(子类)。

例如一个新闻类和一个娱乐类的网页,除了中间部分,网页的头部底部侧栏都是共同属性,使用继承的写法如下:

将公共部分提出来写一个单独的BasePage类,新闻页和娱乐页都可以继承BasePage,类中只需要再单独写content的部分。

#include <string>
#include <iostream>
using namespace std;

//使用继承写法--重复代码都写到基类网页
class BasePage {
public:
	void header() {
		cout << "网页头部" << endl;
	}

	void footer() {
		cout << "网页底部" << endl;
	}

	void left() {
		cout << "网页侧栏" << endl;
	}
};

class News : public BasePage { //继承的写法
public:
	void content() {
		cout << "新闻页" << endl;
	}
};

class YULE : public BasePage {
public:
	void content() {
		cout << "娱乐页" << endl;
	}
};

void test() {//测试
	News news;
	news.footer();

	YULE yl;
	yl.content();
}

int main()
{
	test();
	system("pause");
	return 0;
}

五、继承方式

  • 继承语法:
class 子类名 : 继承方式 父类名 {
    //子类新增的数据成员和成员函数
};
  • 三种继承方式:1.public:公有继承 2.private:私有继承 3.protected:保护继承。

保护属性和私有属性只能类内访问,不能类外访问。

六、继承中的对象模型

子类中会继承父类的私有成员,只是被编译器隐藏了起来,所以访问不到。

例如,下面运行sizeof(Son)时会显示16,而不是12。

class Base{
public:
    int m_A;
protected:
    int m_B;
private:
    int m_C;
};

class Son : public Base{
public:
    int m_D;
};

七、继承中的构造与析构

继承类进行对象声明,构造函数和析构函数的调用顺序如下:

  • 父类构造函数调用
  • 子类构造函数调用
  • 子类析构函数调用
  • 父类析构函数调用

子类会继承父类的成员函数和成员属性,但是子类不会继承父类的构造函数和析构函数。

#include <iostream>
using namespace std;

class Base{
public:
    Base() {
        cout <<"Base的默认构造函数调用" << endl;
    }

    ~Base() {
        cout <<"Base的析构函数调用" << endl;
    }
};


class Son : public Base {
public:
    Son() {
        cout <<"Son的默认构造函数调用" << endl;
    }
    ~Son() {
        cout <<"Son的析构函数调用" << endl;
    }
};


void test() {
    Son s1;
}


int main() {
    test();
    system("pause");
    return 0;
}

如果父类没有默认构造函数,子类可以通过初始化列表的方式显式的调用父类的其他构造。

class Base2{
public:
    Base2(int a) {
        this->m_A = a;
        cout << "有参构造函数的调用" << endl;
    }

    int m_A;
}

class Son2 : public Base2{
public:
    Son2(int a) : Base2(a) {
    }
}

八、继承中的同名成员处理

如果子类和父类拥有同名的函数和属性,如果用子类对象调用就会默认调用子类的函数和属性,调用父类时需要通过作用域进行同名成员的区分:

Son s1;
s1.Base::fun();

如果子类与父类的成员函数名称相同,子类会把父类的所有同名版本(不论参数情况)都隐藏, 想调用父类方法必须加作用域。

注:

  1. 构造函数和析构函数不能被继承;
  2. operator=不能被继承。

九、继承中的静态成员处理

静态对象在类内声明,类外初始化;非静态成员只能用对象调用。

静态成员属性可以被子类继承,如果子类中有同名成员,会把父类的隐藏,静态成员函数同理。

#include <string>
#include <iostream>
using namespace std;

class Base {
public:
	static void func() {
		cout << "Base的func()函数" << endl;
	}

	static void func(int a) {
		cout << "Base的func(int)函数" << endl;
	}

	static int m_A;
};
//静态成员在类内定义,类外初始化
int Base::m_A = 10;

class Son : public Base {
public:
	static void func() {
		cout << "Son的func()函数" << endl;
	}

	static int m_A;
};
int Son::m_A = 20;

void test() {
	cout << Son::m_A; //20
	cout << Base::m_A; //10

	Son::func(); //访问子类的静态成员函数
	Son::Base::func(10); //通过子类访问父类的静态成员函数
}

int main()
{
	test();
	system("pause");
	return 0;
}

十、多继承的概念以及问题

可以从一个类继承,也可以同时从多个类继承,继承多个基类就称为多继承,但是从多个类中继承时可能会由于函数、变量等同名问题导致过多的歧义,出现二义性需要使用作用域进行访问。

多继承使用逗号做拼接,语法如下:

class A : public B1, public B2;

十一、菱形继承和虚继承

菱形继承:两个派生类继承同一个基类而又有某个类同时继承这两个派生类,这种继承被称为菱形继承或者钻石继承。

 菱形继承带来的问题:

  1. C1和C2都继承了Base的数据,D继承C1和C2,当D调用函数或数据时,就会产生二义性。
  2. D继承的Base函数和数据继承了两份,但是这些数据只需要一份就可以。

 菱形问题的解决方案:利用虚继承

  1. 在继承时加virtual关键字,此时为虚基类
  2. D的内部结构:vbptr虚基类指针指向虚基类表;通过虚基类表能找到共有的数据的偏移量
#include <string>
#include <iostream>
using namespace std;

class Base {
public:
	int m_A;
};

//虚基类
class C1 :virtual public Base{

};
//虚基类
class C2 :virtual public Base {

};

class D :public C1, public C2 {

};

//菱形继承的解决办法--虚继承
void test() {
	D d;
	d.C1::m_A = 10;
	d.C2::m_A = 20;
	//使用虚继承之后,只有一份m_A,操作的都是同一份数据
	cout << d.C1::m_A << endl; //20
	cout << d.C2::m_A << endl; //20
	//不加作用域不会有二义性
	cout << d.m_A << endl;
}

int main()
{
	test();
	system("pause");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/134047.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SD存储卡接口规范介绍

SD存储卡简介 SD卡高度集成闪存&#xff0c;具备串行和随机存取能力。可以通过专用优化速度的串行接口访问&#xff0c;数据传输可靠。接口允许几个卡垛叠&#xff0c;通过他们的外部连接。接口完全符合最新的消费者标准&#xff0c;叫做SD卡系统标准&#xff0c;由SD卡系统规范…

用javascript分类刷leetcode14.排序算法(图文视频讲解)

常见排序算法复杂度 n^2除nlogn在不同数据规模下的结果 常见排序算法 算法可视化来源&#xff1a;http://visualgo.net/ 冒泡排序&#xff1a;时间复杂度O(n^2) 比较相邻元素&#xff0c;如果第一个比第二个大&#xff0c;则交换他们一轮下来&#xff0c;可以保证最后一个数…

Android入门第56天-在Android里使用OKHttp多线程下载文件并展示其进度

简介 OkHttp是一个神器。OkHttp分为异步、同步两种调用。今天我们就会基于OkHttp的异步调用实现一个多线程并行下载文件并以进度条展示总进度的实用例子。当然这不是我们的Android里使用OkHttp的最终目标&#xff0c;我们最终在下一篇中会在今天这一课的基础上加入“断点续传”…

【我在异世界学Linux】认识冯诺依曼体系结构

文章目录一、冯诺依曼体系结构是什么二、冯诺依曼为什么要这么设计&#xff1f;三、内存是怎么提高效率的呢&#xff1f;解释&#xff1a;程序要运行&#xff0c;必须加载到内存四、和QQ好友聊天的时候&#xff0c;数据是怎么流向的&#xff1f;一、冯诺依曼体系结构是什么 冯诺…

教你使用Java开发一款简单的扫雷小游戏 附实例代码

相信很多小伙伴都知道也玩过扫雷游戏,本篇文章将和大家分享一篇关于如何使用Java来实现一款简单的扫雷小游戏,这有助于大家对于Java相关知识的学习有一定的参考价值,下面是详情内容。 简介 学了几周的Java,闲来无事,写个乞丐版的扫雷,加强一下Java基础知识。 编写过程…

树莓派4b串口配置

从树莓派的相关资料我们可以看到&#xff0c;树莓派有两个串口可以使用&#xff0c;一个是硬件串口&#xff08;/dev/ttyAMA0&#xff09;,另一个是mini串口&#xff08;/dev/ttyS0&#xff09;。硬件串口有单独的波特率时钟源&#xff0c;性能好&#xff0c;稳定性强&#xff…

【Java寒假打卡】Java基础-接口

【Java寒假打卡】Java基础-接口接口的介绍接口的定义和特点接口中的成员特点JDK8 接口中的成员特点JDK9 接口中的成员特点类和接口的关系接口的介绍 &emsp&#xff1b;当一个类中的所有方法都是抽象方法的时候&#xff0c;我们就可以将其定义为接口&#xff0c;接口也是一…

Redis 缓存数据库

目录Redis 高可用方案高可用概念Redis 高可用的实现方案1、主从模式2、哨兵模式3、集群模式Redis 高可用方案 高可用概念 高可用&#xff08;High Availability&#xff0c;既HA&#xff09;&#xff0c;指的是通过尽量缩短日常维护操作和减少突发系统奔溃锁导致的停机时间来提…

Vagrant 安装 Centos7

首先准备VirtualBox, 当前实验版本为&#xff1a;7.0.4-154605-Win&#xff1b; 再次下载Vagrant windows版本&#xff1a;当前实验版本&#xff1a;vagrant_2.3.4_windows_i686 如果安装VirtualBox过程中提示缺少&#xff1a;Microsoft Visual C 2019 Redistributable &…

MySQL索引概述

索引的英文名叫 index 在数据库是一种帮助MySQL高效获取数据的数据结构 而且是一种有序的数据结构 在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用(指向)数据&#xff0c; 这样就可以在这些数据结构上实现高级找…

公钥基础设施 时间戳规范测评

声明 本文是学习信息安全技术 公钥基础设施 标准符合性测评. 下载地址而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 公钥基础设施 时间戳规范测评 时间戳的产生和颁发 申请和颁发方式 测评依据见GB/T 20520—2006中6.1的内容。 开发者应提供文档…

2.0、Linux-基础了解

2.0、开机关机和基本目录介绍 开机登录&#xff1a; 开会机会启动许多程序&#xff1b;他们在Windows叫做 "服务" &#xff0c;在 Linux 中叫做 "守护进程"&#xff08;daemon&#xff09;&#xff1b; 开机成功后&#xff0c;他会显示一个文本登录…

Tailoring Self-Supervision for Supervised Learning-读后总结

Tailoring Self-Supervision for Supervised Learning摘要文章思路一些值得读的参考文献和技术&#xff1a;值得一读的高引文献可视化技术摘要 近期&#xff0c;在监督学习中部署一个合适的自监督学习来提高监督学习的性能是一个具有前景的方式。然而&#xff0c;因为之前的前…

MP中定义全局常量用于xml的判断,List<String> list = new ArrayList<>(Arrays.asList(“test“));

,1.普通方式 mybatis-plus.configuration.variables.secretFilterSwitch0 yml的方式 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.demo configuration: variables: userId: 456132465 userName: 李四 配置完成后在代…

人文社科类文献去哪些数据库检索下载

查找下载人文社科类文献的数据库大盘点&#xff1a; 1、文献党下载器&#xff08;wxdown.org&#xff09; 大型文献馆&#xff0c;几乎整合汇集了所有中外文献数据库资源&#xff0c;可附带权限进入文献数据库查找下载文献&#xff0c;覆盖全科包括查找下载人文社科类文献的众…

【C和数据结构-5+1】习题第一天

文章目录一.选择题1.整型在内存中的存储2.大小端字节序3.指针的大小4.形参一级指针或二级指针的区别5.二维数组传参降维成数组指针二.编程题1.自守数2.质数判断一.选择题 1.整型在内存中的存储 猜一猜打印的结果? int main() {char a 101;int sum 200;a 27; sum a;printf…

2023年,无所谓,我会出手整合SSM

目录 一、简介&#xff1a; 二、Maven构建框架&#xff1a; 三、依赖配置 四、web.xml配置文件 五、创建SpringMVC的配置文件 六、Spring.xml配置环境 七、其他配置 八、Mapper.xml配置文件&#xff1a; 九、mybatis-config.xml配置文件&#xff1a; 十、log4j.xml日志…

Dropout详解:Dropout解决过拟合问题

Dropout 是一种能够有效缓解过拟合的正则化技术&#xff0c;被广泛应用于深度神经网络当中。但是被 dropout 所丢掉的位置都有助于缓解过拟合的吗&#xff1f; 中山大学 和 Meta AI 在 NeurIPS 2022 接收的论文在研究了注意力中的 dropout 后发现&#xff1a;不同注意力位置对过…

C++string类介绍

目录 一、介绍 二、string类对象的构造 string类有如下构造方法&#xff1a; 类对象的容量操作 类对象访问及遍历 string对象的修改操作&#xff1a; std::string::insert std::string::erase std::string::c_str std::string::find std::string::substr 一、介绍…

Linux学习笔记 超详细 0基础学习(上)

定义 linux是一个操作系统&#xff0c;与Windows、macos一样&#xff0c;是常见的操作系统之一&#xff0c;一般服务器会部署在Linux操作系统中&#xff0c;稳定应用广泛&#xff0c;Android系统是基于Linux内核的&#xff0c;所以了解Linux相关知识对于程序员来说是很重要的。…