C++基础从0到1入门编程(四)类和对象
系统学习C++
方便自己日后复习,错误的地方希望积极指正
往期文章:
C++基础从0到1入门编程(一)
C++基础从0到1入门编程(二)
C++基础从0到1入门编程(三)
参考视频:
1.黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难
2.系统化学习C++
1 从结构体到类
面向对象编程,一切都是对象,对象用类来描述
类:成员变量(属性)和函数(操作方法)
class 类名
{
public:成员1的数据类型 成员名1;成员2的数据类型 成员名2;...成员n的数据类型 成员名n;
}
用类定义一个类的变量:创建(或实例化)一个对象
对象的成员变量和成员函数的作用域和生命周期与对象的作用域和生命周期相同
#include <iostream>
using namespace std;
class CGirl
{
public:string name;int age;void setvalue(string name, int age);void show(){cout << "name = " << name << endl << "age = " << age << endl;}
};
void CGirl::setvalue(string name, int age)
{this->name = name;this->age = age;
}
int main()
{CGirl girl;girl.setvalue("BigDavid", 23);girl.show();return 0;
}
2 类的访问权限
类的成员访问权限:public、private、protected
在类的内部,无论成员声名为何种权限,都可以访问
在类的外部(定义类的代码之外的代码),只能访问public成员
#include <iostream>
using namespace std;
class CGirl
{
private:string name;int age;
public:void setvalue(string name, int age);
};
void CGirl::setvalue(string name, int age)
{this->name = name;this->age = age;
}
int main()
{CGirl girl;girl.setvalue("BigDavid", 23); // 可以通过return 0;
}
(1)在一个类定义中,private和public可以出现多次
(2)结构体成员缺省为public,类成员缺省为private
(3)private的意义在于隐藏类的数据和实现,把需要向外暴露的成员声名为public
3 简单使用类
(1)类的成员函数可以直接访问该类其他的成员函数(可以递归)
#include <iostream>
using namespace std;
class CGirl
{
private:string name;int age;int times = 0;
public:void setvalue(string name, int age){this->name = name;this->age = age;show();}void show(){if (times++ > 10) return;cout << name << ' ' << age << endl;show();}
};int main()
{CGirl girl;girl.setvalue("BigDavid", 23);return 0;
}
(2)类的成员函数可以重载,可以用默认参数
(3)类的成员可以是任意数据类型(类中枚举)
class CGirl
{
private:string name;int age;int times = 0;enum sex {girl = 1, boy = 2};
public:void setvalue(string name, int age){this->name = name;this->age = age;show();}void show(){if (times++ > 10) return;cout << name << ' ' << age << endl;show();}
};
(4)可以为类的成员指定缺省值
(5)类可以创建对象数组
(6)对象可以作为实参传递给函数,一般传引用
(7)用new动态创建对象,用delete释放对象
(8)在类的外部,一般不直接访问(读和写)对象的成员,而是用成员函数。数据隐藏是面向对象编程的思想
(9)对象一般不用memset()清空成员变量,可以写一个专用于清空成员变量的成员函数
class CGirl
{
private:string name;int age;int times = 0;enum sex {girl = 1, boy = 2};
public:void setvalue(string name, int age){this->name = name;this->age = age;show();}void initdata(){name.clear();age = 0;}void show(){if (times++ > 10) return;cout << name << ' ' << age << endl;show();}
};
(10)对类和对象用sizeof运算意义不大,一般不用
(11)用结构体描述纯粹的数据,用类描述对象
(12)在类的声明中定义的函数都将自动成为内联函数;在类的声明之外定义的函数如果使用了inline限定符,也是内联函数
(14)区分类的成员变量和成员函数的形参,把成员变量名加m_前缀或_后缀,如 m_name, name_
(15)类分文件编写
4 构造函数和析构函数
构造函数:在创建对象时,自动的进行初始化工作
语法:类名(){...}
可以有参数,可以重载,可以有默认参数
创建对象只会自动调用一次,不能手工调用
析构函数:在销毁对象前,自动完成清理工作
语法:~类名(){...}
没有参数,不能重载
销毁对象前只会自动调用一次,但可以手工调用
构造函数的细节
(1)如果没有提供构造/析构函数,编译器将提供空实现的构造/析构函数
(2)如果提供了构造/析构,编译器将不提供空的构造/析构函数
(3)创建对象时,如果重载了构造函数,编译器根据实参匹配相应的构造函数。没有参数的构造函数也叫默认构造函数
(4)创建对象的时候不要在对象名后面加空的圆括号,编译器误认为是声明函数。(如果没有构造函数、构造函数没有参数、构造函数的参数都有默认参数)
(5)在构造函数名后面加括号和参数不是调用构造函数,是创建匿名对象
(6) 接受一个参数的构造函数允许使用赋值语法将对象初始化为一个值(可能会导致问题)
CGirl girl = 10;
(7)第一行代码构造函数和析构函数调用一次,下面两行调用两次
CGirl girl = CGirl("西施"20); // 显式创建对象。
CGirl girl; // 创建对象。
girl = CGirl("西施"20); // 创建匿名对象,然后给现有的对象赋值
(8)用new/delete创建/销毁对象时,也会调用构造/析构函数
(9)不建议在构造/析构函数中写太多的代码,可以调用成员函数。
(10)除了初始化,不建议让构造函数做其他工作
(11)C++11支持使用统一的初始化列表
CGirl girl = {"BigDavid", 8};
CGirl girl {"BigDavid", 8};
CGirl* girl = new CGirl{"BigDavid", 8};
(12)如果类的成员也是类,创建对象的时候,先构造成员类;销毁对象的时候,先析构自身,再析构成员类
5 拷贝构造函数
用一个已经存在的对象创建新的对象,不会调用(普通)构造函数,会调用拷贝构造函数。
如果类中没有定义拷贝构造函数,编译器将提供一个拷贝构造函数,它的功能是把已存在对象的成员变量赋值给新对象的成员变量
类名 新对象名(已存在的对象名)
类名 新对象名 = 已存在的对象名
拷贝构造函数的语法:
类名(const 类名& 对象名){...}
Tip:
(1)访问权限必须是public
(2)函数名必须与类名相同
(3)如果类中定义了拷贝构造函数,编译器将不提供默认的拷贝构造函数
(4)以值传递的方式调用函数时,如果实参为对象,会调用拷贝构造函数
(5)函数以值的方式返回对象时,可能会调用拷贝构造函数(VS会调用,Linux不会,g++编译器做了优化)
(6)拷贝构造函数可以重载,可以有默认参数
类名(......,const 类名& 对象名,......){......}
(7)如果类中重载了拷贝构造函数却没有定义默认的拷贝构造函数,编译器也会提供默认的拷贝构造函数
6 浅拷贝和深拷贝

(1)如果一个对象修改了内存中的数据,会影响另一个对象
(2)其中一个对象释放了内存,另一个对象的指针就成了野指针
#include <iostream>
using namespace std;class CGirl
{
public:string m_name;int m_age;int* m_ptr;CGirl(){m_name.clear();m_age = 0;m_ptr = nullptr;cout << "gouzaohanshu\n";}CGirl(const CGirl& gg){m_name = gg.m_name;m_age = gg.m_age;m_ptr = gg.m_ptr;}~CGirl(){delete m_ptr;m_ptr = nullptr;cout << "123\n";}void show(){cout << m_name << ' ' << m_age << ' ' << *m_ptr << endl;}
};int main()
{CGirl g1;g1.m_name = "BigDavid";g1.m_age = 23;g1.m_ptr = new int(3);g1.show();CGirl g2(g1);*g2.m_ptr = 8;g1.show();g2.show();
}

指针A指向一块内存,重新分配一块相同大小的内存,让指针B指向新内存。再把指针A指向的内存中的数据拷贝到新内存中
CGirl(const CGirl& gg)
{m_name = gg.m_name;m_age = gg.m_age;m_ptr = gg.m_ptr;
}
修改上面代码
CGirl(const CGirl& gg)
{m_name = gg.m_name;m_age = gg.m_age;// 分配内存m_ptr = new int;// *m_ptr = *gg.m_ptr; // 拷贝数据memcpy(m_ptr, gg.m_ptr, sizeof(int)); // 拷贝数据
}
7 初始化列表
构造函数的执行分为两个阶段:初始化阶段和计算阶段
初始化阶段先于计算阶段执行
构造函数除了有形参列表和函数体之外,还可以有初始化列表。
初始化列表的语法:
类名(形参列表):成员1(值),成员2(值),...,成员n(值) {...}
Tip:
(1)如果成员已经在初始化列表中,则不应该在构造函数中再次赋值,会覆盖之前初始化列表的值
(2)初始化列表中的括号可以是具体值,也可以是构造函数的形参名,还可以是表达式
(3)初始化列表与赋值有本质的区别,如果成员是类,使用初始化列表调用的是成员类的拷贝构造函数,而赋值则是先创建成员类的对象(将调用成员类的普通构造函数),然后再赋值
(4)成员是类,初始化列表对性能略有提升
(5)如果成员是常量和引用,必须使用初始列表,因为常量和引用只能在定义的时候初始化
(6)如果成员是没有默认构造函数的类,则必须使用初始化列表
(7)拷贝构造函数也可以有初始化列表
(8)类的成员变量可以不出现在初始化列表中
(9)构造函数的形参先于成员变量初始化
#include <iostream>
using namespace std;class CBoy
{
public:string m_xm;CBoy(){m_xm.clear();cout << "CBoy()\n";}CBoy(string xm){m_xm = xm;cout << "CBoy(string xm)\n";}CBoy(const CBoy& bb){m_xm = bb.m_xm;cout << "CBoy(const CBoy &bb)\n";}
};
class CGirl
{
public:string m_name;const int m_age;CBoy m_boy;CGirl(string name, int age, CBoy &boy):m_name(name), m_age(age) , m_boy(boy){//m_boy.m_xm = boy.m_xm;cout << "CGirl(name,age,boy)\n";}void show(){cout << m_name << ' ' << m_age << ' ' << m_boy.m_xm << endl;}
};int main()
{CBoy boy("BigDavid");CGirl g1("qwe", 18, boy);g1.show();
}
8 对象和类 - const修饰成员函数
在类的成员函数后面加const关键字,表示在成员函数中保证不会修改调用对象的成员变量
(1)mutable可以突破const限制,被mutable修饰的成员变量,将永远处于可变的状态
(2)非const函数可以调用const和非const函数
(3)const成员函数不能调用非const成员函数
(4)非const对象可以调用const修饰的成员函数和非const修饰的成员函数
(5)const对象只能调用const修饰的成员函数,不能调用非cosnt修饰的成员函数
Tip:
const CGirl g1("asd", 18);
g1.show();
常对象只能访问加了const的成员函数
创建g1时,上面代码相当于访问了构造函数,但是构造函数没有加const,也没有报错,如果给构造函数加了const,报错了,原因是构造函数或析构函数不允许使用类型限定符
9 this指针
如果类的成员函数涉及多个对象,在这种情况下需要使用this指针
this指针存放了对象的地址,被作为隐藏参数传递给了成员函数,指向调用成员函数的对象(调用者对象)
每个成员函数(包括构造函数和析构函数)都有一个this指针,可以用它访问调用者对象的成员。可以解决成员变量名和函数形参名相同的问题
int aa;
void func(int aa)
{this->aa = aa;
}
*this可以表示对象
如果在成员函数的括号后面使用const,那么将不能通过this指针修改成员变量
#include <iostream>
using namespace std;class CGirl
{
public:string m_name;int m_yz;CGirl(const string &name, int yz){m_name = name;m_yz = yz;}void show() const{cout << m_name << " beautiful\n";}const CGirl& pk(const CGirl& g) const{if (g.m_yz < m_yz) return g;return *this;}
};int main()
{CGirl g1("a", 5);CGirl g2("b", 6);CGirl g3("c", 1);const CGirl& g = g1.pk(g2).pk(g3); // c beautifulg.show();
}
10 类的静态成员
类的静态成员:静态成员变量和静态成员函数
静态成员可以实现多个对象之间的数据共享,比全局变量更安全
static关键字把类的成员变量声名为静态,表示在程序中(不仅是对象)是共享的
静态成员变量不会在创建对象的时候初始化,必须在程序的全局区用代码清晰的初始化(用范围解析运算符 ::)
静态成员使用类名加范围解析运算符 :: 就可以访问,不需要创建对象。
如果把类的成员声明为静态的,就可以把它与类的对象独立开来(静态成员不属于对象)
静态成员变量在程序中只有一份(生命周期与程序运行期相同,存放在静态存储区的),不论是否创建了类的对象,也不论创建了多少个类的对象
静态成员函数,只能访问静态成员,不能访问非静态成员
非静态成员函数可以访问静态成员
静态成员函数没有this指针
const静态成员变量可以在定义类的时候初始化
#include <iostream>
using namespace std;class CGirl
{static int m_age;
public:string m_name;CGirl(const string& name, int age){m_name = name;m_age = age;}void show(){cout << "name: " << m_name << endl;}static void showage(){cout << m_age << endl;}
};int CGirl::m_age = 22;int main()
{CGirl g1("a", 21), g2("b", 23), g3("c", 24);g1.show(); g1.showage();g2.show(); g2.showage();g3.show(); g3.showage();CGirl::showage();
}
11 简单对象模型
C语言本身没有支持数据和函数之间的关联性,数据和处理数据的操作是分开的。
C++用类描述抽象数据类型(ADT),在类中定义了数据和函数,把数据和函数关联起来
对象维护了多个指针表,表中存放了成员和地址的对应关系

数据成员:非静态、静态
函数成员:非静态、静态、virtual
对象内存的大小:
(1)所有非静态数据成员的大小
(2)由内存对齐而填补的内存大小
(3)支持virtual成员而产生的额外负担
静态成员变量属于类,不计算在对象的大小之内
成员函数是分开存储的,不论对象是否存在都占用存储空间,在内存中只有一个副本,也不计算在对象大小之内
用空指针可以调用没有用到this指针的非静态成员函数(如果成员函数中没有用到非静态成员变量,就可以用空指针调用它)
在没有创建对象的情况下,访问非静态成员变量就是访问空指针
#include <iostream>
#include <cstring>
using namespace std;class CGirl
{
public:char m_name[3];int m_bh;static int m_age;CGirl(){memset(m_name, 0, sizeof(m_name)); m_age = 0;}~CGirl() {}void showname(){//if (this == nullptr) return;cout << "asd" << endl;}void showage(){cout << m_age << endl;}
};int CGirl::m_age;
int aaa;
void func() {}int main()
{CGirl g;CGirl* g1 = nullptr;g1->showname(); // asd
}
对象的地址是第一个非静态成员变量的地址,如果类中没有非静态成员变量,编译器会隐含的增加一个1字节的占位成员
相关文章:
C++基础从0到1入门编程(四)类和对象
系统学习C 方便自己日后复习,错误的地方希望积极指正 往期文章: C基础从0到1入门编程(一) C基础从0到1入门编程(二) C基础从0到1入门编程(三) 参考视频: 1.黑马程序员匠心…...
如何有效解决UDP协议传输问题实现快速安全的文件传输
随着互联网技术的不断发展,UDP协议作为一种快速、简单的传输协议被广泛应用于文件传输领域。然而,UDP协议传输过程中也存在着一些问题,如传输速度不稳定、数据丢失等,这些问题会影响到文件传输的效率和安全性。本文将介绍UDP协议传…...
Mac下载的软件显示文件已损坏,如何解决文件已损坏问题,让文件可以正常运行
Mac下载的软件显示文件已损坏,如何解决文件已损坏问题,让文件可以正常运行 设备/引擎:Mac(11.6)/Mac Mini 开发工具:终端 开发需求:让显示已损坏的文件顺利安装到电脑 大家肯定都遇到过下载…...
实战 - 在Linux上部署各类软件
前言 为什么学习各类软件在Linux上的部署 在前面,我们学习了许多的Linux命令和高级技巧,这些知识点比较零散,同学们跟随着课程的内容进行练习虽然可以基础掌握这些命令和技巧的使用,但是并没有一些具体的实操能够串联起来这些知…...
Jenkins扩展篇-流水线脚本语法
JenkinsFile可以通过两种语法来声明流水线结构,一种是声明式语法,另一种是脚本式语法。 脚本式语法以Groovy语言为基础,语法结构同Groovy相同。 由于Groovy学习不适合所有初学者,所以Jenkins团队为编写Jenkins流水线提供一种更简…...
一个ETL流程搞定数据脱敏
数据脱敏是什么? 数据脱敏是指在数据处理过程中,通过一系列的技术手段去除或者替换敏感信息,以保护个人隐私和敏感信息的安全的过程。数据脱敏通常在数据共享、数据分析和软件测试等场景下使用,它旨在降低数据泄露和滥用的风险。…...
重生奇迹mu迹辅助什么好
主流辅助一号选手:弓箭手 智弓作为最老、最有资历的辅助职业,一直都是各类玩家的首要选择。因为智力MM提供的辅助能力都是最基础、最有效、最直观的辅助。能够减少玩家对于装备的渴求度,直接提升人物的攻防,大大降低了玩家升级打…...
【bug 回顾】上传图片超时
测试 bug 问题分析 - 上传图片超时 最近在测试上遇到一个莫名奇妙的问题,最后也没有得到具体是哪块的原因,看各位大佬有没有思路?? 一 、背景 现在我们有三台服务器,用来布两套环境。其中另外一台服务器3配置的 tom…...
Leetcode1410. HTML 实体解析器
Every day a Leetcode 题目来源:1410. HTML 实体解析器 解法1:模拟 遍历字符串 text,每次遇到 ’&‘,就判断以下情况: 双引号:字符实体为 " ,对应的字符是 " 。单引号&a…...
【Django使用】django经验md文档10大模块。第4期:Django数据库增删改查
Django的主要目的是简便、快速的开发数据库驱动的网站。它强调代码复用,多个组件可以很方便的以"插件"形式服务于整个框架,Django有许多功能强大的第三方插件,你甚至可以很方便的开发出自己的工具包。这使得Django具有很强的可扩展…...
SAP LU04记账更改通知单创建转储单报错:L3094 记帐修改没有份存在
解决办法: 使用事务码LU02,修改过账更改状态,将过账更改状态改为U,强制关闭 1. LU04 查找记账更改通知单号 2. 事务码LU02修改状态 这个时候再用LU04去查看的时候,就不会再显示了...
Redis:Java客户端
前言 "在当今大数据和高并发的应用场景下,对于数据缓存和高效访问的需求日益增长。而Redis作为一款高性能的内存数据库,以其快速的读写能力和丰富的数据结构成为众多应用的首选。与此同时,Java作为广泛应用于企业级开发的编程语言&…...
使用electron工具打包web端到PC端应用程序
根据electron官网快速入门示例可以方便的构建mac端包,我们在此基础上构建windows端exe包. 1在package.json文件的script字段增加以下配置 "scripts": {..."build": "electron-builder --win"}, 2然后在终端执行以下命令 npm run b…...
Django框架环境的搭建(图文详解)
目录 day01 Web框架和Django基础 1.web框架底层 1.1 网络通信编辑 1.2 常见软件架构 1.3 手撸web框架 2.web框架 2.1 wsgiref 2.2 werkzeug 2.3 各框架的区别 3.快速上手django框架 3.1 安装 3.2 命令行 3.3 Pycharm 4.虚拟环境 4.1 创建虚拟环境 - 命令行 4…...
Java接口自动化测试系列[V1.0.0][概述]
基础知识 在TCP/IP中,HTTP属于传输层协议,该协议采用的是Request-Response的模式,且该协议是无状态的,也就是后续如果要用到前面的信息必须重新请求重新获取;HTTP通过SSL/TSL加密成为HTTPS,与HTTP相比HTTP…...
indexedDB存储
使用 setDBData({ id: name, value: 张三, expire: new Date().getTime() 10000 }, info, infoDB) console.log(getDBData(name, info, infoDB)); 添加或更新数据 async function setDBData(data,storeName "storeName",dbName "dbName",version ) {c…...
双向绑定与单向数据流之争,Solid会取代React吗
现在有一种观点声音逐渐大了起来,认为市面上出现了许多比 React 性能更好的框架,是不是意味着,React 将要被淘汰了? 谈谈我的看法,来做一个深入一点的分析 先说结论:Solid.js 要取代 React 很难 1 双向…...
Java --- JVM之垃圾回收相关知识概念
目录 一、System.gc() 二、内存溢出与内存泄漏 2.1、内存溢出 2.2、内存泄漏 三、Stop the world 四、垃圾回收的并行与并发 4.1、并发 4.2、并行 4.3、并行 vs 并发 4.4、垃圾回收的并发与并行 五、安全点与安全区域 5.1、安全点 5.2、安全区域 六、引用 6.1…...
单节点服务架构
单节点的服务架构: LNMP l:lilnux系统 n:nginx静态页面,转发动态请求 m:mysql数据库,后端服务器,保存用户和密码信息,以及论坛的信息 p:PHP,处理动态请求,动态请求转发数据库,然…...
Ubuntu Server download
前言 Ubuntu——公共云、数据中心和边缘上最受欢迎的 Linux 发行版。自成立以来,Ubuntu 一直在获得市场份额,截至今天已接近 50%。 Ubuntu Server download VersionUbuntu Server 其它主机型号版本Ubuntu AMD历史版下载百度云Ubuntu Server all Ubuntu…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
