C++基础学习(2)

news2024/11/27 21:33:49

C++基础学习

  • 一、运算符重载
    • 1.1 加号运算符的重载
    • 1.2 左移运算符的重载
    • 1.3 递增运算符的重载
    • 1.4 赋值运算符的重载
    • 1.5 关系运算符的重载
  • 二、继承
    • 2.1 继承的基本用法
    • 2.2 继承方式
    • 2.3 继承当中的对象模型
    • 2.4 继承当中的构造和析构函数的顺序
    • 2.5 继承同名成员处理方式
    • 2.6继承同名静态成员处理方式
    • 2.7 多继承语法
  • 三、多态
    • 3.1 多态的基本概念
    • 3.2 纯虚函数和抽象类

一、运算符重载

运算符重载概念:对已有的迷算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

1.1 加号运算符的重载

作用:

实现两个自定义数据类型相加的运算

#include<stdio.h>
#include<iostream>
using namespace std;

//重载运算符
class Person {
public:
	//成员函数重载+法运算符
	/*Person operator+(Person &p) {
		Person temp;
		temp.m_A = this->m_A + p.m_A;
		temp.m_B = this->m_B + p.m_B;
		return temp;
	}*/
public:
	int m_A;
	int m_B;
	Person() {};
	Person(int a,int b) {
		m_A = a;
		m_B = b;
	}

};

//通过全局来重载+法运算符
Person operator+ (Person & p1, Person & p2) {
	Person temp;
	temp.m_A = p1.m_A + p2.m_A;
	temp.m_B = p1.m_B + p2.m_B;

	return temp;
}

//还可以创建类似的+法重载函数
Person operator+ (Person& p1, int num) {
	Person temp;
	temp.m_A = p1.m_A + num;
	temp.m_B = p1.m_B + num;

	return temp;
}

void test() {
	Person p1(10, 10);
	Person p2(20, 30);

	Person p3 = p1 + p2;

	cout << "p3.m_B = " << p3.m_B << endl;
	cout << "p3.m_A = " << p3.m_A << endl;

	Person p4 = p2 + 100;
	cout << "p4.m_B = " << p4.m_B << endl;
	cout << "p4.m_A = " << p4.m_A << endl;
}

int main() {
	test();
}

总结:

  • 总结1:对于内置的数据类型的表达式的的运算符是不可能改变的
  • 总结2:不要滥用运算符重载

1.2 左移运算符的重载

左移运算符:>>

作用:

可以输出自定义数据类型

#include<stdio.h>
#include<iostream>
using namespace std;

class Person {
public:
	//创建成员函数去调用<<重载,不可行,因为只能让cout在其右侧,重载不出来
	/*ostream& operator<<(ostream& cout) {
		cout << this->m_A << " " << this->m_B;
		return cout;
	}*/

public:
	int m_A;
	int m_B;

	Person(int a, int b) {
		m_A = a;
		m_B = b;
	}
};

ostream& operator<<(ostream& cout, Person& p) {
	cout << p.m_A << " " << p.m_B;
	return cout;
}
void test() {
	Person p(10, 20);
	/*p.operator<<(cout);
	若用成员函数只能写成这样
	*/

	//我们应该重写为下面的形式
	cout << p;

}

int main() {
	test();
}

总结: 重载左移运算符配合友元可以实现输出自定义数据类型

1.3 递增运算符的重载

作用

通过重载递增运算符,实现自己的整型数据

#include<stdio.h>
#include<iostream>
using namespace std;

class MyInteger {
public:
	int MyNum;

	MyInteger() {
		MyNum = 0;
	}
	//++前置
	MyInteger& operator++() {
		//先将数字++;
		MyNum++;
		//再返回其数字
		return *this;
	}

	//后置++,通过后面是否跟上int占位符,跟着就为后置

	MyInteger operator++(int) {//这里必须是返回值,因为这里返回的是临时变量,调用后就会消失

		//首先创建一个临时变量来存储值,用作后面的返回
		MyInteger temp = *this;

		MyNum++;
		return temp;
	}
};

ostream& operator<<(ostream& cout,MyInteger p) {
	cout << p.MyNum;
	return cout;
}

void test() {
	/*MyInteger p1;
	cout<< ++p1 << endl;
	cout << p1;*/

	MyInteger p2;
	cout << p2++ << endl;
	cout << p2 << endl;
}

int main() {
	test();
}

1.4 赋值运算符的重载

c++编译器至少给一个类添加4个函数

  1. 默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝构造函数,对属性进行值拷贝
  4. 赋值运算符 operator=,对属性进行值拷贝

为什么要进行赋值运算符的重载:

如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题

#include<stdio.h>
#include<iostream>
using namespace std;

class Person {
public:
	int* m_age;

	Person(int age) {
		this->m_age = new int(age);
	}

	//重载赋值运算符(必须返回的为引用数据类型)
	Person& operator= (Person& p) {
		//如之前的有数字的话,你们就先将其清理干净后在进行深拷贝
		if (m_age != NULL) {
			delete m_age;
			m_age = NULL;
		}

		//进行深拷贝方法
		m_age = new int(*p.m_age);

		return *this;//(返回当前的Person类,才能够进行链式编程)
	}

	~Person() {
		if (this->m_age != NULL) {
			delete m_age;
			m_age = NULL;
		}
	}

	
};

void test() {
	Person p2(20);
	Person p1(30);
	Person p3(30);

	p1 = p2 = p3;

	cout << "p1 = " << *p1.m_age << endl;
	cout << "p2 = " << *p2.m_age << endl;
	cout << "p3 = " << *p3.m_age << endl;
}

int main() {
	test();

}

1.5 关系运算符的重载

作用: 重载关系运算符,可以让两个自定义类型对象进行对比操作

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;

class Person {
public:
	string m_name;
	int m_age;
	Person(string name, int age) {
		this->m_age = age;
		this->m_name = name;
	}

	//进行重载运算符
	bool operator== (Person& p) {
		if (( this->m_age == p.m_age) && (this->m_name = p.m_name)) {
			return true;
		}
		else return false;
	}
};

void test() {
	Person p1("asd", 12);
		Person p2("asd", 12);

		if ( p1 == p2) {
			cout << "他们相等" << endl;
		}
		else {
			cout << "他们不相等" << endl;
		}
}

int main() {
	test();
}

二、继承

继承是面向对象三大特性之一
在这里插入图片描述

  • 我们发现,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性.
  • 这个时候我们就可以考虑利用继承的技术,减少重复代码

2.1 继承的基本用法

总结:

可以减少重复的代码继承的好处:

语法
class A : public B;

  • A 类称为子类派生类
  • B类称为父类基类

派生类中的成员,包含两大部分:

  • 类是从基类继承过来的,一类是自己增加的成员
  • 从基类继承过过来的表现其共性,而新增的成员体现了其个性

2.2 继承方式

继承的语法: class 子类 : 继承方式 父类

继承方式一共有三种:

  • 公共继承
  • 保护继承
  • 私有继承

在这里插入图片描述

public继承如下 ,其他的类似

#include<stdio.h>
#include<iostream>
using namespace std;

class Base {
public:
	int age;
protected:
	int ID;
private:
	int height;
};

class son1 :public Base {
public:
	son1 s1() {
		age = 100;//可以修改
		ID = 15;//可以修改
		//height = 180; //不能出现
	}
};

	void test1() {
		son1 s1;
		s1.age = 100;//可以在类外修改
		//s1.ID = 15;//不可以
		//s1.height = 180; //不能
	}

	int main() {
		test1();
	}

2.3 继承当中的对象模型

说明:

  • 父类中所有非静态成员属性都会被子类继承下去
  • 父类中私有成员属性 是被编译器给隐藏了,因此是访问不到,但是确实被继承下去了

2.4 继承当中的构造和析构函数的顺序

  • 首先先创建父类的构造函数,在创建子类的构造函数
  • 析构函数的顺序是与构造函数的调用方法相反

2.5 继承同名成员处理方式

问题: 当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?
  • 访问子类同名成员直接访问即可
  • 访问父类同名成员需要加作用域
#include<stdio.h>
#include<iostream>
using namespace std;

class Base {
public:
	int age;

	void func() {
		cout << "父类的func:函数的调用" << endl;
	}
	void func(int a) {
		cout << "父类的func:(int a)函数的调用" << endl;
	}
};

class Son :public Base {
public:
	int age;
	void func() {
		cout << "子类的func函数:调用" << endl;
	}
};

void test() {
	Son s1;

	//调用子类的func函数
	s1.func();

	//s1.func(10); 这里会报错,因为这里表示的为调用子类的有参成员函数,只有父类才有有参的成员
	//函数,当未加上与解析符的时候,那么会覆盖子类的所有成员函数

	//调用父类的func函数
	s1.Base::func();
	s1.Base::func(10);
}

int main() {
	test();
}

总结:

  1. 子类对象可以直接访问到子类中同名成员
  2. 子类对象加作用域可以访问到父类同名成员
  3. 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数

2.6继承同名静态成员处理方式

问题: 继承中同名的静态成员在子类对象上如何进行访问?
#include<stdio.h>
#include<iostream>
using namespace std;

class Base {
public:
	static void func() {
		cout << "调用Base当中的静态成员函数" << endl;
	}
	static void func(int a ) {
		cout << "调用Base(int a)当中的静态成员函数" << endl;
	}

	static int age;
};

int Base::age = 100;

class Son : public Base {
public:
	static void func() {
		cout << "调用Son当中的静态成员函数" << endl;
	}
	

	static int age;

};

int Son::age = 200;

void test() {
	//1. 通过成员函数来调用
	Son s1;

	cout << "调用子类的成员属性" << s1.age << endl;
	cout << "调用父类的成员属性" << s1.Base::age << endl;
	s1.func();
	s1.Base::func();


	//2.通过类名来调用
	cout << "调用子类的成员属性" << Son::age<< endl;
	cout << "调用父类的成员属性" << Son::Base::age<< endl;
	Son::func();
	Son::Base::func();
	
}

int main() {
	test();
}

静态成员和非静态成员出现同名,处理方式一致

  • 访问子类同名成员 直接访问即可
  • 访问父类同名成员 需要加作用域

总结:

同名静态成员处理方式和非静态处理方式一样,只不过有两种访问的方式(通过对象和通过类名)

2.7 多继承语法

C++允许一个类继承多个类

语法: class 子类 : 继承方式 ,父类1继承方式 父类2...

多继承可能会引发父类中有同名成员出现,需要加作用域区分

C++实际开发中不建议用多继承

#include<stdio.h>
#include<iostream>
using namespace std;

class Base1 {
public:
	int age;
};

class Base2 {
public:
	int age;
};

class Son : public Base1, public Base2 {
public:
	int a;
	int b;

	Son() {
		Base1::age = 100;
		Base2::age = 320;
		a = 1;
		b = 1;
	}
};

void test() {
	Son s1;

	cout << "Base1类当中的age: " << s1.Base1::age << endl;
	cout << "Base2类当中的age: " << s1.Base2::age << endl;
}

int main() {
	test();
}

总结: 多继承中如果父类中出现了同名情况,子类使用时候要加作用域

三、多态

3.1 多态的基本概念

多态是C++面向对象三大特性之一

多态分为两类

  • 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
  • 动态多态: 派生类和虚函数实现运行时多态

静态多态和动态多态区别:

  • 静态多态的函数地址早绑定 编译阶段确定函数地址
  • 动态多态的函数地址晚绑定 运行阶段确定函数地址

实现多态的条件

1、有继承关系
2、子类重写父类的虚函数

动态多态使用父类的指针或者引用 指向子类对象

下面通过案例进行讲解多态

#include<stdio.h>
#include<iostream>
using namespace std;

class Animal {
public:
	virtual void speak(Animal& a) {
		cout << "动物在说话" << endl;
	}
};

class Cat :public Animal {
public:
	//重写虚函数,但是重写父类的虚函数对象与重载不同,返回值,参数必须完全相同
	void speak(Animal& a) {
		cout << "小猫在说话" << endl;
	}
};

void test() {
	Cat cat;
	cat.speak(cat);
}

int main() {
	test();
}

3.2 纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容

  • 因此可以将虚函数改为纯虚函数

  • 纯虚函数语法: virtual 返回值类型 函数名(参数列表) = 0;

  • 当类中有了纯虚函数,这个类也称为抽象类

抽象类特点

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类

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

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

相关文章

希尔排序—C语言实现

目录 前言 希尔排序 发展历史 基本思想 时间复杂度 &#x1f970;我们以一组数字来说操作说明&#xff1a; gap的选取 动图演示 代码&#xff1a; 总结&#xff1a; 前言 &#x1f970;在学数据结构的第一节课就知道了数据结构课程是要管理并且学会操作数据&#xff0c;…

对应分析——SPSS实例分析

对应分析是R型因子分析和Q型因子分析的结合。本质是将列联表里面的频数数据作变换&#xff08;通过降维的方法&#xff09;以后&#xff0c;利用二维图的方式&#xff0c;简单直观的表示行变量和列变量之间的相关性&#xff0c;适合于多分类型变量的研究。数据展示如下&#xf…

20利用灰色神经网络预测6个月订单需求(附matlab程序)

1.简述 学习目标&#xff1a;灰色神经网络预测订单需求 灰色系统理论是一种研究少数据、贫信息、不确定性问题的新方法&#xff0c;它以部分信息已知&#xff0c;部分信息未知的“小样本”&#xff0c;“贫信息”不确定系统为研究对象&#xff0c;通过对“部分”已知信息的生成…

Web服务器群集:部署LNMP平台

目录 一、理论 1.LNMP平台 2.Nginx服务基础 3.Nginx访问控制 4.Nginx虚拟主机 二、实验 1.LNMP架构DISCUZ论坛应用 三、问题 1.没有规则可以创建“default”需要的目标“build”。 四、总结 一、理论 1.LNMP平台 &#xff08;1&#xff09;概念 LNMP平台是高效稳定的…

LinkedList(1):链表介绍和单向链表的实现

1 链表介绍 链表的分类&#xff1a;单链表&#xff0c;双链表&#xff0c;循环链表 链表&#xff1a;由链将一个个元素连接&#xff0c;每一个元素我们通常将其称之为Node 节点Node 节点&#xff1a;由两部分组成 数据值的变量 Node next 用来存放下一个节点的Node 对象 pack…

redis zrange 与 zrangebyscore的区别

redis zrange 与 zrangebyscore的区别 目录 redis zrange 与 zrangebyscore的区别前言先说概念上的结论&#xff1a;实验数据准备对比案例一对比结论&#xff1a;对比案例二对比结论&#xff1a; 总结 前言 想做一个在redis中获取数据时分页的功能&#xff0c;从网上查找到了z…

【C/C++数据结构与算法】C语言预处理

目录 一、源文件到可执行程序的过程 二、预处理详解 1. 预定义符号 2. #define 3. 条件编译 一、源文件到可执行程序的过程 预处理&#xff1a;去注释&#xff0c;宏替换&#xff0c;头文件展开&#xff0c;条件编译编译&#xff1a;c语言 ---> 汇编语言&#xff08;语…

软考高级系统架构设计师(二) 基础知识之计算机组成与系统结构

目录 概要 计算机组成结构 CPU组成 冯诺依曼结构 存储系统-层次化存储结构 高速缓冲存储器cache 主存编址计算 磁盘管理 磁盘管理算法 先来先服务&#xff08;FCFS&#xff09;&#xff1a; 最短寻道时间优先&#xff08;SSTF&#xff09; 扫描算法&#xff08;电梯调度…

【VisualStudio】使用 C++ 语言开发 Qt 环境配置教程

文章目录 1. 安装 Visual Studio2. 安装 Qt3. 联合Ref 先上一张效果图&#xff0c;具体步骤主要分为以下三步。 1. 安装 Visual Studio 这一步不再赘述&#xff0c;注意一定要安装 C 语言。 可以参考这个教程 Visual Studio 2022安装与使用教程。 2. 安装 Qt 这一步也不再赘…

DAY10_HTTPTomcatServlet

目录 1 Web概述1.1 Web和JavaWeb的概念1.2 JavaWeb技术栈1.2.1 B/S架构1.2.2 静态资源1.2.3 动态资源1.2.4 数据库1.2.5 HTTP协议1.2.6 Web服务器 2 HTTP2.1 简介2.2 请求数据格式2.2.1 格式介绍2.2.2 实例演示 2.3 响应数据格式2.3.1 格式介绍2.3.2 响应状态码2.3.2.1 状态码大…

vue+element-ui初体验入门拥有自己的前台项目以及配置文件讲解(2)组件式开发,路由,请求发送

阿丹&#xff1a; 前面的文章已经进行了vue的组件安装&#xff0c;本篇文章来了解一下vue的语句语法以及element-ui的具体用法。并使用全局的守卫路由来完成用户完成登录来请求头携带token 导入axios以及导入element-ui 按照图片指引来到main.js将我们前面文章下载的组件进行…

基于matlab将天线工具箱与相控阵系统配合使用(附源码)

一、前言 创建天线阵列&#xff08;如均匀线性阵列 &#xff08;ULA&#xff09;&#xff09;时&#xff0c;可以使用相控阵系统工具箱中内置的天线。或者&#xff0c;您可以使用天线工具箱天线。天线工具箱天线提供物理天线的真实模型。它们是使用力矩的方法设计的。相控阵天线…

自动化测试工具 AirTest 的使用方法与简介

目录 前言&#xff1a; Airtest简介 1.基于图像识别的Airtest框架 2.基于UI识别的Poco框架 Airtest环境搭建 Airtest布局 Airtest使用步骤 第一步&#xff1a;连接移动设备 第二步&#xff1a;创建一个.air文件&#xff08;也就是我们的测试脚本&#xff09; 第三步&#xff1a…

相机去畸变

1. 背景 在做图像感知工作过程中会遇到需要处理相机畸变的情况&#xff0c;如SLAM、3D重建等&#xff0c;则需要了解一些常见相机模型的成像过程&#xff0c;以及依据成像过程实现去除相机成像的畸变。 注意&#xff1a;这篇文章并不涉及太多相机参数畸变原理&#xff0c;更多…

Vicuna模型权重合成及模型部署

第一式&#xff1a;Vicuna模型部署 1.环境搭建1.1 构建虚拟环境1.2 安装FastChat1.2.1 利用pip直接安装1.2.2 从github下载repository然后安装 2.Vicuna Weights合成2.1 下载vicuna delta weights2.2 下载原始llama weights2.3 合成真正的working weights2.3 填坑手册 3. 使用命…

第九章 os模块

1. os模块介绍 os 模块是Python 内置的与操作系统中的文件系统相关的模块&#xff0c;该模块依赖于操作系统。通常情况下&#xff0c;如不特别指出&#xff0c;该模块提供的方法、属性在Windows 和UNIX 系统上都是可用的。其中&#xff0c;UNIX 系统包括Linux 和Mac OS X 说明…

软件加密类型及原理特点总结

目录 一、软件加密目的 二、加密方式介绍 2.1 硬件加密 2.2 软件加密 三、软件加密方式 3.1非对称加密算法 3.2对称加密算法 四、数字签名 五、软件破解方式 参考文献 一、软件加密目的 防止软件被复制使用并恶意破坏&#xff0c;给企业和个人带来经济损失。 二、加密方…

杂记 | 使用Docker和Nginx为网站添加HTTPS访问功能

文章目录 01 准备工作1.1 HTTPS介绍1.2 准备工作 02 编写nginx.conf03 使用docker启动nginx 01 准备工作 1.1 HTTPS介绍 HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;是一种通过加密通信保护网站数据传输的协议。它是 HTTP 协议的安全版本&#xff0c;通…

ROS下写服务

话题和服务的对比&#xff1a; 1.话题 话题是单向的&#xff0c;而且不需要等待服务端上线&#xff0c;直接发就行&#xff0c;数据的实时性比较高。 频率高&#xff0c;实时性强的传感器数据的传递一般使用话题实现。 话题通信是ROS中使用频率最高的一种通信模式&#xff0c…

人工智能之后,量子计算将成为下一趋势

光子盒研究院 人工智能显然是席卷科技行业的最新热潮&#xff0c;但一个更大的趋势可能即将到来&#xff0c;那就是量子计算——只要它能解决令人不安的网络安全问题。 量子计算的进展似乎注定要使今天的基于电子芯片的超级计算机逊色。这些机器在亚原子水平上工作&#xff0c;…