首页IT科技c++核心技术(c++核心编程)

c++核心技术(c++核心编程)

时间2025-05-02 00:11:54分类IT科技浏览3543
导读:序言 本文章主要介绍C++面向对象编程技术做了详细的讲解...

序言

本文章主要介绍C++面向对象编程技术做了详细的讲解

1.内存分区模型

代码区:存放函数体的二进制代码            ,由操作系统进行管理的 全局区:存放全局变量和静态变量以及常量 栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

内存四区意义:

不同区域存放的数据                   ,赋予不同的生命周期, 给我们更大的灵活编程

1.1程序运行前

在程序编译后      ,生成了exe可执行程序         ,未执行该程序前分为两个区域

代码区:

​ 存放 CPU 执行的机器指令

​ 代码区是共享的                   ,共享的目的是对于频繁被执行的程序         ,只需要在内存中有一份代码即可

​ 代码区是只读的      ,使其只读的原因是防止程序意外地修改了它的指令

全局区:

​ 全局变量和静态变量存放在此.

​ 全局区还包含了常量区, 字符串常量和其他常量也存放在此.

​ 该区域的数据在程序结束后由操作系统释放.

总结: C++中在程序运行前分为全局区和代码区 代码区特点是共享和只读 全局区中存放全局变量             、静态变量                  、常量 常量区中存放 const修饰的全局常量 和 字符串常量

1.2程序运行后

栈区:

由编译器自动分配释放, 存放函数的参数值,局部变量等

注意事项:不要返回局部变量的地址                   ,栈区开辟的数据由编译器自动释放

堆区:

​由程序员分配释放,若程序员不释放,程序结束时由操作系统回收

在C++中主要利用new在堆区开辟内存

总结:

堆区数据由程序员管理开辟和释放

堆区数据利用new关键字进行开辟内存

1.3 new操作符

​ C++中利用new操作符在堆区开辟数据

​ 堆区开辟的数据             ,由程序员手动开辟   ,手动释放                  ,释放利用操作符 delete

​ 语法: new 数据类型

​ 利用new创建的数据                ,会返回该数据对应的类型的指针

示例1: 基本语法

int* func() { int* a = new int(10); return a; } int main() { int *p = func(); cout << *p << endl; cout << *p << endl; //利用delete释放堆区数据 delete p; //cout << *p << endl; //报错,释放的空间不可访问 system("pause"); return 0; }

示例2:开辟数组

//堆区开辟数组 int main() { int* arr = new int[10]; for (int i = 0; i < 10; i++) { arr[i] = i + 100; } for (int i = 0; i < 10; i++) { cout << arr[i] << endl; } //释放数组 delete 后加 [] delete[] arr; system("pause"); return 0; }

2 引用

2.1 引用的基本使用

**作用:**给变量起别名

语法: 数据类型 &别名 = 原名

示例:

int main() { int a = 10; int &b = a; cout << "a = " << a << endl; cout << "b = " << b << endl; b = 100; cout << "a = " << a << endl; cout << "b = " << b << endl; system("pause"); return 0; }

2.2 引用注意事项

引用必须初始化 引用在初始化后               ,不可以改变

示例:

int main() { int a = 10; int b = 20; //int &c; //错误                   ,引用必须初始化 int &c = a; //一旦初始化后   ,就不可以更改 c = b; //这是赋值操作            ,不是更改引用 cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; system("pause"); return 0; }

2.3 引用做函数参数

**作用:**函数传参时                   ,可以利用引用的技术让形参修饰实参

**优点:**可以简化指针修改实参

示例:

//1. 值传递 void mySwap01(int a, int b) { int temp = a; a = b; b = temp; } //2. 地址传递 void mySwap02(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } //3. 引用传递 void mySwap03(int& a, int& b) { int temp = a; a = b; b = temp; } int main() { int a = 10; int b = 20; mySwap01(a, b); cout << "a:" << a << " b:" << b << endl; mySwap02(&a, &b); cout << "a:" << a << " b:" << b << endl; mySwap03(a, b); cout << "a:" << a << " b:" << b << endl; system("pause"); return 0; }

总结:通过引用参数产生的效果同按地址传递是一样的             。引用的语法更清楚简单

2.4 引用做函数返回值

作用:引用是可以作为函数的返回值存在的

注意:不要返回局部变量引用

用法:函数调用作为左值

示例

//返回局部变量引用 int& test01() { int a = 10; //局部变量 return a; } //返回静态变量引用 int& test02() { static int a = 20; return a; } int main() { //不能返回局部变量的引用 int& ref = test01(); cout << "ref = " << ref << endl; cout << "ref = " << ref << endl; //如果函数做左值      ,那么必须返回引用 int& ref2 = test02(); cout << "ref2 = " << ref2 << endl; cout << "ref2 = " << ref2 << endl; test02() = 1000; cout << "ref2 = " << ref2 << endl; cout << "ref2 = " << ref2 << endl; system("pause"); return 0; }

2.5 引用的本质

本质:引用的本质在c++内部实现是一个指针常量.

2.6 常量引用

**作用:**常量引用主要用来修饰形参         ,防止误操作

在函数形参列表中                   ,可以加const修饰形参         ,防止形参改变实参

3.函数提高

4.类与对象

C++面向对象的三大特性为:封装      、继承          、多态

C++认为万事万物都皆为对象      ,对象上有其属性和行为

例如:

​ 人可以作为对象                   ,属性有姓名                  、年龄         、身高       、体重…             ,行为有走                   、跑            、跳   、吃饭                   、唱歌…

​ 车也可以作为对象   ,属性有轮胎               、方向盘、车灯…,行为有载人                、放音乐                  、放空调…

​ 具有相同性质的对象                  ,我们可以抽象称为类                ,人属于人类,车属于车类

4.1封装

4.1.1 封装的意义

封装是C++面向对象三大特性之一

封装的意义:

将属性和行为作为一个整体               ,表现生活中的事物 将属性和行为加以权限控制

封装意义一:

​ 在设计类的时候                   ,属性和行为写在一起   ,表现事物

语法: class 类名{ 访问权限: 属性 / 行为 };

封装意义二:

类在设计时            ,可以把属性和行为放在不同的权限下                   ,加以控制

访问权限有三种:

public 公共权限 类内可以访问 类外可以访问 protected 保护权限 类内可以访问 类外不可以访问 private 私有权限 类内可以访问 类外不可以访问

4.1.2 struct和class区别

在C++中 struct和class唯一的区别就在于 默认的访问权限不同

区别:

struct 默认权限为公共 class 默认权限为私有

4.2 对象的初始化和清理

生活中我们买的电子产品都基本会有出厂设置      ,在某一天我们不用时候也会删除一些自己信息数据保证安全 C++中的面向对象来源于生活         ,每个对象也都会有初始设置以及 对象销毁前的清理数据的设置                  。

4.2.1 构造函数和析构函数

对象的初始化和清理也是两个非常重要的安全问题

​ 一个对象或者变量没有初始状态                   ,对其使用后果是未知

​ 同样的使用完一个对象或变量         ,没有及时清理      ,也会造成一定的安全问题

c++利用了构造函数析构函数解决上述问题                   ,这两个函数将会被编译器自动调用             ,完成对象初始化和清理工作      。

对象的初始化和清理工作是编译器强制要我们做的事情   ,因此如果我们不提供构造和析构                  ,编译器会提供

编译器提供的构造函数和析构函数是空实现          。

构造函数:主要作用在于创建对象时为对象的成员属性赋值                ,构造函数由编译器自动调用,无须手动调用                  。 析构函数:主要作用在于对象销毁前系统自动调用               ,执行一些清理工作         。

构造函数语法:类名(){}

构造函数                   ,没有返回值也不写void 函数名称与类名相同 构造函数可以有参数   ,因此可以发生重载 程序在调用对象时候会自动调用构造            ,无须手动调用,而且只会调用一次

析构函数语法: ~类名(){}

析构函数                   ,没有返回值也不写void 函数名称与类名相同,在名称前加上符号 ~ 析构函数不可以有参数      ,因此不可以发生重载 程序在对象销毁前会自动调用析构         ,无须手动调用,而且只会调用一次

示例

class Person { public: //构造函数 Person() { cout << "Person的构造函数调用" << endl; } //析构函数 ~Person() { cout << "Person的析构函数调用" << endl; } }; void test01() { Person p; } int main() { test01(); system("pause"); return 0; }

4.2.2 构造函数的分类及调用

两种分类方式:

​ 按参数分为: 有参构造和无参构造

​ 按类型分为: 普通构造和拷贝构造

三种调用方式:

​ 括号法

​ 显示法

​ 隐式转换法

示例

//1   、构造函数分类 // 按照参数分类分为 有参和无参构造 无参又称为默认构造函数 // 按照类型分类分为 普通构造和拷贝构造 class Person { public: //无参(默认)构造函数 Person() { cout << "无参构造函数!" << endl; } //有参构造函数 Person(int a) { age = a; cout << "有参构造函数!" << endl; } //拷贝构造函数 Person(const Person& p) { age = p.age; cout << "拷贝构造函数!" << endl; } //析构函数 ~Person() { cout << "析构函数!" << endl; } public: int age; }; //2             、构造函数的调用 //调用无参构造函数 void test01() { Person p; //调用无参构造函数 } //调用有参的构造函数 void test02() { //2.1 括号法                   ,常用 Person p1(10); //注意1:调用无参构造函数不能加括号         ,如果加了编译器认为这是一个函数声明 //Person p2(); //2.2 显式法 Person p2 = Person(10); Person p3 = Person(p2); //Person(10)单独写就是匿名对象 当前行结束之后      ,马上析构 //2.3 隐式转换法 Person p4 = 10; // Person p4 = Person(10); Person p5 = p4; // Person p5 = Person(p4); //注意2:不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明 //Person p5(p4); } int main() { test01(); //test02(); system("pause"); return 0; }

4.2.3 拷贝构造函数调用时机

C++中拷贝构造函数调用时机通常有三种情况

使用一个已经创建完毕的对象来初始化一个新对象 值传递的方式给函数参数传值 以值方式返回局部对象

4.2.4 构造函数调用规则

默认情况下                   ,c++编译器至少给一个类添加3个函数

1.默认构造函数(无参             ,函数体为空)

2.默认析构函数(无参   ,函数体为空)

3.默认拷贝构造函数                  ,对属性进行值拷贝

构造函数调用规则如下:

如果用户定义有参构造函数                ,c++不在提供默认无参构造,但是会提供默认拷贝构造

如果用户定义拷贝构造函数               ,c++不会再提供其他构造函数

4.2.5 深拷贝与浅拷贝

深浅拷贝是面试经典问题                   ,也是常见的一个坑

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区重新申请空间   ,进行拷贝操作

总结:如果属性有在堆区开辟的            ,一定要自己提供拷贝构造函数                   ,防止浅拷贝带来的问题

4.2.6 初始化列表

作用:

C++提供了初始化列表语法      ,用来初始化属性

语法:构造函数():属性1(值1),属性2(值2)... {}

4.4 友元

生活中你的家有客厅(Public)         ,有你的卧室(Private)

客厅所有来的客人都可以进去                   ,但是你的卧室是私有的         ,也就是说只有你能进去

但是呢      ,你也可以允许你的好闺蜜好基友进去       。

在程序里                   ,有些私有属性 也想让类外特殊的一些函数或者类进行访问             ,就需要用到友元的技术

友元的目的就是让一个函数或者类 访问另一个类中私有成员

友元的关键字为 friend

友元的三种实现

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

4.4.1 全局函数做友元

class Building { //告诉编译器 goodGay全局函数 是 Building类的好朋友   ,可以访问类中的私有内容 friend void goodGay(Building * building); public: Building() { this->m_SittingRoom = "客厅"; this->m_BedRoom = "卧室"; } public: string m_SittingRoom; //客厅 private: string m_BedRoom; //卧室 }; void goodGay(Building * building) { cout << "好基友正在访问: " << building->m_SittingRoom << endl; cout << "好基友正在访问: " << building->m_BedRoom << endl; } void test01() { Building b; goodGay(&b); } int main(){ test01(); system("pause"); return 0; }

4.5 运算符重载

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

示例:

class Person { public: Person() {}; Person(int a, int b) { this->m_A = a; this->m_B = b; } //成员函数实现 + 号运算符重载 Person operator+(const 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 operator+(const Person& p1, const Person& p2) { // Person temp(0, 0); // temp.m_A = p1.m_A + p2.m_A; // temp.m_B = p1.m_B + p2.m_B; // return temp; //} //运算符重载 可以发生函数重载 Person operator+(const Person& p2, int val) { Person temp; temp.m_A = p2.m_A + val; temp.m_B = p2.m_B + val; return temp; } void test() { Person p1(10, 10); Person p2(20, 20); //成员函数方式 Person p3 = p2 + p1; //相当于 p2.operaor+(p1) cout << "mA:" << p3.m_A << " mB:" << p3.m_B << endl; Person p4 = p3 + 10; //相当于 operator+(p3,10) cout << "mA:" << p4.m_A << " mB:" << p4.m_B << endl; } int main() { test(); system("pause"); return 0; }

4.6继承

4.6.1 继承的基本语法

例如我们看到很多网站中,都有公共的头部               ,公共的底部                   ,甚至公共的左侧列表   ,只有中心内容不同

接下来我们分别利用普通写法和继承的写法来实现网页中的内容            ,看一下继承存在的意义以及好处

普通实现: //Java页面 class Java { public: void header() { cout << "首页                  、公开课      、登录          、注册...(公共头部)" << endl; } void footer() { cout << "帮助中心                  、交流合作         、站内地图...(公共底部)" << endl; } void left() { cout << "Java,Python,C++...(公共分类列表)" << endl; } void content() { cout << "JAVA学科视频" << endl; } }; //Python页面 class Python { public: void header() { cout << "首页       、公开课                   、登录            、注册...(公共头部)" << endl; } void footer() { cout << "帮助中心   、交流合作                   、站内地图...(公共底部)" << endl; } void left() { cout << "Java,Python,C++...(公共分类列表)" << endl; } void content() { cout << "Python学科视频" << endl; } }; //C++页面 class CPP { public: void header() { cout << "首页               、公开课、登录                、注册...(公共头部)" << endl; } void footer() { cout << "帮助中心                  、交流合作   、站内地图...(公共底部)" << endl; } void left() { cout << "Java,Python,C++...(公共分类列表)" << endl; } void content() { cout << "C++学科视频" << endl; } }; void test01() { //Java页面 cout << "Java下载视频页面如下: " << endl; Java ja; ja.header(); ja.footer(); ja.left(); ja.content(); cout << "--------------------" << endl; //Python页面 cout << "Python下载视频页面如下: " << endl; Python py; py.header(); py.footer(); py.left(); py.content(); cout << "--------------------" << endl; //C++页面 cout << "C++下载视频页面如下: " << endl; CPP cp; cp.header(); cp.footer(); cp.left(); cp.content(); } int main() { test01(); system("pause"); return 0; }

继承实现:

//公共页面 class BasePage { public: void header() { cout << "首页             、公开课                  、登录      、注册...(公共头部)" << endl; } void footer() { cout << "帮助中心          、交流合作                  、站内地图...(公共底部)" << endl; } void left() { cout << "Java,Python,C++...(公共分类列表)" << endl; } }; //Java页面 class Java : public BasePage { public: void content() { cout << "JAVA学科视频" << endl; } }; //Python页面 class Python : public BasePage { public: void content() { cout << "Python学科视频" << endl; } }; //C++页面 class CPP : public BasePage { public: void content() { cout << "C++学科视频" << endl; } }; void test01() { //Java页面 cout << "Java下载视频页面如下: " << endl; Java ja; ja.header(); ja.footer(); ja.left(); ja.content(); cout << "--------------------" << endl; //Python页面 cout << "Python下载视频页面如下: " << endl; Python py; py.header(); py.footer(); py.left(); py.content(); cout << "--------------------" << endl; //C++页面 cout << "C++下载视频页面如下: " << endl; CPP cp; cp.header(); cp.footer(); cp.left(); cp.content(); } int main() { test01(); system("pause"); return 0; }

总结:

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

class A : public B;

A 类称为子类 或 派生类

B 类称为父类 或 基类

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

一类是从基类继承过来的      ,一类是自己增加的成员                   。

从基类继承过过来的表现其共性         ,而新增的成员体现了其个性            。

4.6.2 继承方式

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

继承方式一共有三种:

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

4.7 多态

4.7.1 多态的基本概念

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

多态分为两类

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

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

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

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

class Animal { public: //Speak函数就是虚函数 //函数前面加上virtual关键字         ,变成虚函数      ,那么编译器在编译的时候就不能确定函数调用了   。 virtual void speak() { cout << "动物在说话" << endl; } }; class Cat :public Animal { public: void speak() { cout << "小猫在说话" << endl; } }; class Dog :public Animal { public: void speak() { cout << "小狗在说话" << endl; } }; //我们希望传入什么对象                   ,那么就调用什么对象的函数 //如果函数地址在编译阶段就能确定             ,那么静态联编 //如果函数地址在运行阶段才能确定   ,就是动态联编 void DoSpeak(Animal & animal) { animal.speak(); } // //多态满足条件: //1         、有继承关系 //2       、子类重写父类中的虚函数 //多态使用: //父类指针或引用指向子类对象 void test01() { Cat cat; DoSpeak(cat); Dog dog; DoSpeak(dog); } int main() { test01(); system("pause"); return 0; }

总结:

多态满足条件

有继承关系 子类重写父类中的虚函数

多态使用条件

父类指针或引用指向子类对象

重写:函数返回值类型 函数名 参数列表 完全一致称为重写

声明:本站所有文章                  ,如无特殊说明或标注                ,均为本站原创发布                   。任何个人或组织,在未征得本站同意时               ,禁止复制                   、盗用            、采集   、发布本站内容到任何网站                   、书籍等各类媒体平台               。如若本站内容侵犯了原著者的合法权益                   ,可联系我们进行处理。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
用python如何做大小写转换(python中有哪些大小写转换方法) 动漫形象制作(本地生成动漫风格 AI 绘画 图像|Stable Diffusion WebUI 的安装和局域网部署教程)