超详细的 C++中的封装继承和多态的知识总结<1.封装与继承>

引言

  小伙伴们都知道C++面向对象难,可是大家都知道,这个才是C++和C的真正区别的地方,也是C++深受所有大厂喜爱的原因,它的原理更接近底层,它的逻辑更好,但是学习难度高,大家一定要坚持下来呀,本章呢对于C++有关的知识开始讲解封装继承和多态。好了啦废话不多说,跟着小杨一起开始吧!

  冲冲冲!!!!!!

封装

  • 封装的关键字是clas。
  • 从上一章当中,我们已经知道了,封装就是现实生活中的事物定义为类,将事物的数据抽象为属性,将事物的行为抽象为方法。

类的数据成员和成员函数

  • 数据成员
    • 类中的数据成员描述该类对象的属性,数据成员必须在类体中定义,其定义方式须与一般变量相同,但对于数据成员的访问要手访问控制权限的限定。
    • 数据成员的初始化与普通变量的初始化形式有所不同,不能使用圆括号(即对象方式初始化)可以使用=和{ }。
    • 多个数据成员之间不能重名,一个类是一个作用域。
  • 成员函数
    • 成员函数描述类对象的行为,即该类对象的所执行的操作。
    • 一个类的多个同名不同参数类型的成员函数可以重载。
    • 类的成员函数也可以是内联函数。
    • 函数成员参数也可以有默认值。
  • 成员的访问控制
    • private私有访问权限
      • 数据成员和成员函数只允许访问类本身的成员函数访问,对类的外部不可见。
    • protected保护访问权限
      • 数据成员和成员函数允许类本身及其派生类的成员函数访问
    • public共有访问权限
      • 数据成员和成员函数对外类外部可见,类内部也能访问

类的定义代码示例:

#include <iostream>using namespace std;
/*class关键字定义类。类名是标识符,需要满足标识符规范,类名命名规范是大驼峰,每个单词首字母大写,其他字母小写。类名后一对花括号表示类的作用域,也称为类体,分号表示类定义结束。关键字private,protected,public称为访问控制机制。默认为private。
*/
class Rect
{
private://	属性int m_length;int m_width;
public:/*类中的成员函数(方法)可以再类中直接定义,也可以只写函数声明,然后在类的外面写出函数定义。*/	//	方法void setLength(int length);//	函数成员可以内联inline void setWidth(int width = 0);int getArea();int getPerimeter();
};void Rect::setLength(int length)
{m_length = length;
}void Rect::setWidth(int width)
{m_width = width;
}int Rect::getArea()
{return m_width * m_length;
}int Rect::getPerimeter()
{return 2 * (m_width + m_length);
}int main()
{//	定义(创建)Rect类的对象r。Rect r, r1;//	.操作符访问成员,可以访问数据成员或成员函数。r.setLength(2);r.setWidth(3);cout << r.getArea() << endl;cout << r.getPerimeter() << endl;	//	多个对象之间的属性互相独立。r1.setLength(1);//	函数成员参数可以有默认值r1.setWidth();cout << r1.getArea() << endl;cout << r1.getPerimeter() << endl;return 0;
}
  • 类的特殊成员
      在类中,除了一些简单的数据成员和成员函数外,还有一些具有特殊作用,和特殊规范的函数,这些类的特殊成员正是封装的厉害之处,也是满足各种各样要求的一大利器,让我们一起来看一下吧。

构造函数

  • 在创建对象时,利用特定的值构造对象,将对象初始化为一个特定状态。
  • 构造函数也是类的成员函数,除具有一般成员函数的特点外,还有以下特点:
    • 构造函数的函数名和类名相同
    • 不能定义构造函数的类型,因为构造函数没有返回值,也就没有返回值类型。
    • 构造函数不在程序中调用,在对象被创建时,被编译器调用,
    • 构造函数可以被重载
    • 如果类中没有构造函数,则在C++编译器中会默认自动生成一个无参的默认构造函数,一旦用户显示定义任何构造函数,默认构造函数将不再提供。
    • 无论任何方式创建对象,公祖奥函数都会被调用,如果找不到和参数匹配的构造函数,编译器会产生错误。
  • 初始化列表
    • 除了在构造函数体中为数据成员初始化,还可以使用初始化列表对数据成员初始化。
    • 类的常量成员需要初始化时,只能在初始化列表初始化。
  • 构造函数代码示例:
#include <iostream>using namespace std;class Rect
{
private:	int m_length;int m_width;
public:/*构造函数和类同名且没有返回类型。构造函数允许重载。没有定义构造函数时,编译器会提供默认的无参构造函数,当定义任何构造函数后,编译器不再提供默认构造函数。*/Rect();Rect(int length, int width);void setLength(int length);	inline void setWidth(int width = 0);int getArea();int getPerimeter();
};Rect::Rect()
{cout << "Rect::Rect()" << endl;
}Rect::Rect(int length, int width)
{cout << "Rect(int length, int width)" << endl;m_length = length;m_width = width;
}void Rect::setLength(int length)
{m_length = length;
}void Rect::setWidth(int width)
{m_width = width;
}int Rect::getArea()
{return m_width * m_length;
}int Rect::getPerimeter()
{return 2 * (m_width + m_length);
}int main()
{	//	构造函数由编译器在创建对象时调用。Rect r(2, 3);Rect r1;return 0;
}

析构函数

  • 与构造函数相对的就是析构函数,在删除一个对象前被调用,释放该对象的内存空间及其他的一些清理工作。
  • 析构函数的特征
    • 析构函数的名字“~类名”
    • 析构函数没有参数,也不能指定返回类型,一个类只有一个析构函数。
    • 当一个类删除时,编译器会自动调用析构函数。
    • 如果没有显示定义,编译器将默认生成一个默认的析构函数,函数体空。
  • 析构函数代码示例:
#include <iostream>using namespace std;class Circle
{
private:const float PI = 3.1415926;int m_radius;char* m_name = NULL;public:Circle(int radius);Circle(const char* name, int radius);//	声明析构函数~Circle();int getArea();void info();
};//	常量必须使用初始化列表初始化
Circle::Circle(const char* name, int radius)
{int len = strlen(name) + 1;m_name = new char[len];strcpy_s(m_name, len, name);m_radius = radius;
}Circle::Circle(int radius)
{	m_radius = radius;
}Circle::~Circle()
{cout << "Circle::~Circle()";	if(m_name != NULL){cout << m_name;delete[]m_name;}	cout << endl;
}int Circle::getArea()
{return PI * m_radius * m_radius;
}void Circle::info()
{cout << "m_name: " << m_name << " m_radius:" << m_radius << endl;
}int main()
{//	动态分配的对象在使用delete删除时,调用析构函数Circle* p = new Circle("HHH", 2);delete p;//	编译器在栈中创建的对象,在编译器删除对象时调用析构函数,先创建的对象后删除。char c[20] = "test1";Circle circle(c, 1);cout << circle.getArea() << endl;circle.info();c[4] = '2';circle.info();Circle circle1(1);return 0;
}

拷贝构造函数

  • 拷贝构造函数可以实现用一个已存在的对象初始化新对象。
  • 拷贝构造函数的一般格式为:类名(const 类名& 形参名)
  • 拷贝构造函数(自定义)代码示例:
#include <iostream>using namespace std;//	自定义拷贝构造函数
class Circle
{
private:const float PI = 3.1415926;int m_radius;char* m_name = NULL;public:	Circle(const char* name, int radius);/*拷贝构造函数的参数相对固定,常见方式为:(const 类名& 形参名)*/Circle(const Circle& c);~Circle();int getArea();void info();
};Circle::Circle(const char* name, int radius)
{int len = strlen(name) + 1;	  m_name = new char[len];  strcpy_s(m_name, len, name);  m_radius = radius;	
}
//	实现拷贝构造函数
Circle::Circle(const Circle& c)
{int len = strlen(c.m_name) + 1;m_name = new char[len];strcpy_s(m_name, len, c.m_name);m_radius = c.m_radius;	
}Circle::~Circle()
{ccountout << "Circle::~Circle()";if (m_name != NULL){cout << m_name;delete[]m_name;}cout << endl;}int Circle::getArea()
{return PI * m_radius * m_radius;
}void Circle::info()
{cout << "m_name: " << m_name << " m_radius:" << m_radius << endl;	
}int main()
{Circle circle1("C1", 2);circle1.info();Circle circle2(circle1);circle2.info();return 0;
}
  • 拷贝构造函数(默认)代码示例:
#include <iostream>using namespace std;//	使用默认拷贝构造函数
class Circle
{
private:const float PI = 3.1415926;int m_radius;char* m_name = NULL;public:Circle(char* name, int radius);			void info();
};Circle::Circle(char* name, int radius)
{m_name = name;m_radius = radius;
}void Circle::info()
{cout << "m_name: " << m_name << " m_radius:" << m_radius << endl;
}int main()
{char c[] = "C1";Circle circle1(c, 2);circle1.info();Circle circle2(circle1);circle2.info();return 0;
}

赋值函数

  • 用赋值语句将一个对象的值赋给了另一个已有同类对象时,将调用赋值函数。

  • 赋值函数的一般格式:类名&operate=(const类名&形参名)

  • 实现赋值函数时,一般要判断入参是否为对象本身,如果是对象本身,则不进行操作直接返回。

  • 赋值函数代码示例:

#include <iostream>using namespace std;class Circle
{
private:const float PI = 3.1415926;int m_radius;char* m_name = NULL;public:Circle(const char* name, int radius);~Circle();	Circle& operator=(const Circle& c);void info();
};Circle::Circle(const char* name, int radius)
{cout << "Circle::Circle(const char* name, int radius):" << name << endl;int len = strlen(name) + 1;m_name = new char[len];strcpy_s(m_name, len, name);m_radius = radius;
}Circle::~Circle()
{count << "Circle::~Circle()";if (m_name != NULL){cout << m_name;delete[]m_name;}cout << endl;
}//	赋值函数的一般格式
Circle& Circle::operator=(const Circle& c)
{cout << "Circle::operator=(const Circle& c):" << " c.m_name: " << c.m_name << endl;//	赋值函数要判断实参是不是对象本身,如果是对象本身则直接返回。if (this != &c){if (m_name != NULL){delete[] m_name;			}int len = strlen(c.m_name) + 1;m_name = new char[len];strcpy_s(m_name, len, c.m_name);m_radius = c.m_radius;}	//	this是对象的固有指针,指向对象本身。return *this;
}void Circle::info()
{cout << "m_name: " << m_name << " m_radius:" << m_radius << endl;
}int main()
{Circle circle1("C11", 2);circle1.info();Circle circle2("C2", 3);//	调用赋值函数//	circle2 = circle1;circle2 = circle2;circle2.info();return 0;
}

继承

  有关继承的知识点并不是很多,但是继承也是很重要的一环。但是其繁琐的理解的难易程度也不小。

  • 子类继承父类的属性和方法,使得子类具备父类的特征。
  • 继承的类型
    • 单继承:子类只有一个父类(基类)
    • 多继承:子类有多于一个父类(基类)
    • 直接继承:顾名思义,就是他的继承来自他的父类
    • 间接继承:他的继承是通过继承的子类做了父类的继承。
  • 派生类不继承父类的构造方法(构造函数)每个子类都必须实现至少一个构造函数。
  • 方法的隐藏:子类中定义和父类方法名完全相同时,子类的函数屏蔽掉了预期同名的所有父类函数,这叫方法的隐藏。
  • 有关派生类继承的代码示例:
#include <iostream>#include "Pet.h"
#include "Cat.h"
#include "Dog.h"
/*我们在对应的头文件里加上了每个派生类的构造函数,还有私人属性和是实现方法的声明,。同时我们在对应的cpp文件里对函数功能的具体实现。
*/
using namespace std;int main()
{Pet pet("小强", 20);pet.info();pet.barking();pet.barking(3);pet.running();Cat cat("叮当", 10);cat.info();cat.barking();cat.barking(3);cat.running();Dog dog("旺财", 10);dog.info();dog.barking();//	dog.barking(3); 父类Pet类的barking(int n)方法被隐藏了。dog.running();dog.guardHouse();return 0;
}
  • 类的继承方式
    在这里插入图片描述
  • 默认的继承方式是private。
  • 派生类的构造和析构构成
    • 派生类构造函数的执行顺序
      • 调用基类的构造函数执行派生类的构造函数体。
    • 派生类的析构函数执行顺序
      • 执行子类的析构函数调用基类的析构函数
  • 派生类的构造和析构构成代码示例:
#include <iostream>
using namespace std;class Animal
{
protected:int m_age;
public:Animal( age){cout << "Animal(int age): " << endl;m_age = age;}~Animal(){cout << "~Animal() " << endl;}void info(){cout << "Animal: m_age: " << m_age << endl;}
};class Tiger : public Animal
{
private:int m_weight;
public:Tiger(int age, int weight) : Animal(age){cout << "Tiger(int age, int weight) : Animal(age): " << endl;m_weight = weight;}~Tiger(){cout << "~Tiger() " << endl;}void info(){cout << "Tiger: m_age: " << m_age << " m_weight: " << m_weight << endl;}
};int main()
{Tiger tiger(2, 20);return 0;
}
  • 多继承简介
    • 一个派生类可以有很多基类,称之为多继承。
    • 多继承时,可以按照父类声明顺序构造父类,按照构造相反的顺序析构。
  • 多继承代码示例:
#include <iostream>using namespace std;//	基类BaseA
class BaseA
{
protected:int m_a;int m_c = 100;
public:BaseA(int a){cout << "BaseA(int a)" << endl;m_a = a;}~BaseA(){cout << "~BaseA()" << endl;}
};//	基类BaseB
class BaseB
{
protected:int m_b;int m_c = 200;
public:BaseB(int b){cout << "BaseB(int b)" << endl;m_b = b;}~BaseB(){cout << "~BaseB()" << endl;}
};class Derived : public BaseA, public BaseB
{
public:Derived(int a, int b) : BaseB(b), BaseA(a){cout << "Derived(int a, int b) : BaseA(a), BaseB(b)" << endl;}~Derived(){cout << "~Derived()" << endl;}void info(){cout << "m_a: " << m_a << " m_b: " << m_b << endl;//	当多个父类中出现同名成员时,使用 类名::成员名 访问。cout << "BaseA::m_c: " << BaseA::m_c << " BaseB::m_c: " << BaseB::m_c << endl;	}
};int main()
{Derived derived, 20);dervied.info();return 0;
}

结语

  由于篇幅有限,暂不能写完有关继承和多态的知识,剩下的就留着下一篇章,超详细的 C++中的封装继承和多态的知识总结<2.多态>,小伙伴们,虽然没有写完,但是本章的内容也不少,小伙伴们一定要认真复习,这个理解起来挺费劲的,但是也是我们学习后续必不可少的内容。小伙伴们加油呀~
  冲冲冲!!!!

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

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

相关文章

起飞,纯本地实时语音转文字!

简介 偶然在 github 上翻到了这个项目 https://github.com/k2-fsa/sherpa-ncnn 在没有互联网连接的情况下使用带有 ncnn 的下一代 Kaldi 进行实时语音识别。支持 iOS、Android、Raspberry Pi、VisionFive2、LicheePi4A等。 也就是说语音转文字可以不再借助网络服务的接口&am…

mac显示隐藏的.git文件

打开终端 输入命令 defaults write com.apple.finder AppleShowAllFiles YES killall Finder

Python代码设置Excel工作表背景色或背景图

Excel是工作中数据处理和分析数据的重要工具。面对海量的数据和复杂的表格&#xff0c;如何提高工作效率、减少视觉疲劳并提升数据的可读性是不容忽视的问题。而给工作表设置合适的背景是表格优化的一个有效方式。为Excel工作表设置背景色或背景图不仅能够美化工作表&#xff0…

25.labview数据采集中的读取和写入文本文件和Excel表格文件

①本文将会讲解labview读取和写入文本文件和Excel文件的几种不同方式&#xff0c;讲解程序的基本原理&#xff0c;并提出具体的实施方案&#xff0c;本文内容如下所示。 ②本文文章结束会提供大家 文本和表格读取写入的源程序 &#xff0c;以便于大家学习和使用。 本文中可能用…

TYPE-C转DC转接头方案,ECP5701支持5V、9V、12V、15V、20V电压输出

如今随着这几年的USB-C PD适配器的普及&#xff0c;消费者手上的PD适配器越来越普遍&#xff0c;如何让以前的电源适配器也可以用上PD适配器呢&#xff1f;如此一来以前的电源适配器坏了&#xff0c;就不需要费心费力的寻找相同的适配器进行更换&#xff0c;甚至于只能将整个设…

Xilinx FPGA:vivado关于单端ROM的一个只读小实验

一、实验要求 将生成好的voe文件里的数据使用rom读取出来&#xff0c;采用串口工具发送给电脑&#xff08;当按键来临时&#xff09;。 二、程序设计 按键消抖模块&#xff1a; timescale 1ns / 1ps module key_debounce(input sys_clk ,input rst_n…

怎么录制电脑内部声音?好用的录音软件分享,看这篇就够了!

如何录制电脑内部声音&#xff1f;平时使用电脑工作&#xff0c;难免会遇到需要录音的情况。好用的录音软件有很多&#xff0c;也有部分录屏工具也支持录音功能。 那么如何录制电脑内部声音呢&#xff1f;本文整理了几个录制电脑内部声音的方法&#xff0c;如果你需要在电脑上录…

Spring框架的学习SpringMVC(1)

1.什么是MVC (1)MVC其实就是软件架构的一种设计模式&#xff0c;它将软件的系统分为&#xff0c;&#xff08;视图&#xff0c;模型&#xff0c;控制器&#xff09;三个部分 1.1View(视图) 视图也就是&#xff0c;在浏览器显示的那一个部分&#xff0c;是后端数据的呈现 1.…

推荐一个私有化部署的物联网平台

引言 随着物联网技术的飞速发展&#xff0c;越来越多的企业开始寻求能够提供稳定、安全、可定制的物联网解决方案。私有化部署的物联网平台因其能够满足企业对数据安全和个性化需求的优势&#xff0c;逐渐成为市场的新宠。本文将详细介绍ThingsKit物联网平台&#xff0c;一个专…

常见问题记录

conda操作 conda精确查找某个包的版本 conda list 包名下载源 -i https://pypi.mirrors.ustc.edu.cn/simple/conda查看下载源 conda config --show channels下载torch conda install pytorch1.13.0 torchvision0.14.0 torchaudio0.13.0 cpuonlyconda环境没有名字 利用vsc…

【java计算机毕设】美容院管理系统 项目源代码MySQL springboot vue html maven+文档 前后端可分离也可不分离

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】美容院管理系统 项目源代码MySQL springboot vue html maven文档 前后端可分离也可不分离 2项目介绍 系统功能&#xff1a; 美容院管理系统包括管理员、用户俩种角色。 管理员功能包括个人中心模块用于修改…

“第六感”真的存在吗?

现在已有证据表明&#xff0c;人类除视觉、听觉、嗅觉、味觉和触觉五种感觉以外&#xff0c;确实存在“第六感” “第六感”的学术名称为“超感自知觉”(简称ESP)&#xff0c;它能透过正感官之外的渠道接收信息&#xff0c; 预知将要发生的事&#xff0c;而且与当事人之前的经…

向量数据库、主键存储引擎、高速网络 RDMA 框架……DolphinDB 版本更新啦!

盛夏已至&#xff0c;炎热的七月伊始&#xff0c;DolphinDB 也迎来了版本的更新。此次更新的 3.00.1 与 2.00.13 版本从多个维度进行了优化扩展&#xff0c;进一步深化了 DolphinDB 在机器学习、数据分析等领域的尝试与探索。 为了响应用户日益增长的 AI 运算需求&#xff0c;…

C语言自定义类型(结构体,枚举,联合):

大家好久不见&#xff0c;今天我们来学习一下C语言中的自定义类型&#xff1a; C语言的自定义类型包括&#xff1a;结构体&#xff0c;枚举和联合&#xff0c;接下来大家跟我来一起认识一下这三种类型。 目录 1. 结构体 1.1.1 结构体类型的声明 1.1.2 结构的特殊声明 1.1…

钡铼RTU无线S270用于风力发电站机房远程状态监测和故障预警系统集成

在现代风力发电行业中&#xff0c;机房的远程监测和故障预警系统对于保障风力发电机组的稳定运行至关重要。钡铼第4代S270工业级4G远程遥测终端&#xff08;RTU&#xff09;&#xff0c;以其先进的技术和多功能应用&#xff0c;成为风力发电站机房智能化管理的理想选择。 技术…

深入理解计算机系统 CSAPP 8.4.2 fork函数

//fork.c #include <sys/types.h> #include <unistd.h> #include <stdio.h>int main() {pid_t fpid; //fpid表示fork函数返回的值int count 0;fpid fork();if (fpid < 0)printf("error in fork!");else if (fpid 0) {printf("\ni am th…

相机网线RJ45连接器双端带线5米8芯绿色网线注塑成型

相机网线RJ45连接器双端带线5米8芯绿色网线注塑成型&#xff0c;这款网线采用了环保的绿色材质&#xff0c;线长5米&#xff0c;足够满足大多数拍摄场景的需求。更重要的是&#xff0c;它采用了8芯设计&#xff0c;保证了数据传输的稳定性和高速性。在接口方面&#xff0c;它采…

RpcChannel的调用过程

目录 1. RPC调用方&#xff08;caller&#xff09;的调用(消费)过程 2.在caller下创建文件&#xff1a;calluserservice.cc 3.在src的include下创建文件&#xff1a;mprpcchannel.h 4.在src下创建mprpcchannel.cc 1. RPC调用方&#xff08;caller&#xff09;的调用(消费)过…

Android14之RRO资源文件替换策略(二百二十一)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+AOSP…

代码随想录算法训练营第67天:图论5[1]

代码随想录算法训练营第67天&#xff1a;图论5 ‍ 105.有向图的完全可达性 卡码网题目链接&#xff08;ACM模式&#xff09;(opens new window) 【题目描述】 给定一个有向图&#xff0c;包含 N 个节点&#xff0c;节点编号分别为 1&#xff0c;2&#xff0c;…&#xff0…