【C++精华铺】4.C++类和对象(上)面向对象、类、this指针

news2024/9/28 1:19:02

目录

1. 面向过程和面向对象

2. 类的引入

3. 类的定义

 4. 类的访问限定符和封装

4.1 类的访问限定符

4.2 封装

 5. 类的作用域

 6. 类的实例化

7. 类对象模型

7.1 类对象的存储方式

7.2 类的大小

7.2.1 空类的大小

 7.2.2 结构体内存对齐规则

8. this关键字深入讲解

 8.1 this指针的引出

 8.2 this指针的特性

 9.空指针调用成员函数的问题


1. 面向过程和面向对象

        C语言是一门面向过程的语言,面向的解决问题的过程,通过函数调用来依次解决问题:

譬如洗衣服:拿盆-放水-放衣服-放洗衣粉... ...

        而C++是基于面向对象的,关注的是对象,同样拿洗衣服举例C++关注的是:人、衣服、洗衣粉... ...

2. 类的引入

        在C语言中结构体只能定义变量,在C++中结构体被升级成了类,里面不仅可以定义变量,也可以定义函数。

struct Date
{
	void addDate(int x) {}
	int _year;
	int _month;
	int _day;
};

      但是上面的结构体在C++中更愿意用class来定义。

3. 类的定义

        class为定义类的关键字,{}中的内容为类的类体,里面定义的内容称之为成员,类中的变量称之为类的属性或者类的成员变量,ClassName为类名,并且大括号后面的分号”;“一定不能省略。

class ClassName
{
    //类体
};

        类有俩种定义方式: 

  1. 声明和定义全部放在类体中(成员函数在类体中定义,编译器可能会将其作为内联函数处理)
    class Date 
    {
    public:
    	void addDate(int x)
    	{
    		//
    	}
    private:
    	int _year;
    	int _month;
    	int _day;
    };
  2. 类声明放在.h文件中,成员函数定义在.cpp文件中(成员函数前要加上类名::
    #pragma once
    class Date
    {
    public:
    	void addDate(int x);
    
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    
    #include<iostream>
    #include"date.h"
    void Date::addDate(int x)
    {
    	std::cout << "void addDate(int x);";
    }

     4. 类的访问限定符和封装

4.1 类的访问限定符

        

        另外需要注意的是 class 的默认访问权限是 private,而struct的默认访问权限是 public(兼容c语言)

4.2 封装

        面向对象有三大特性:封装、继承、多态。其余俩种会在后续文章中给大家讲到。今天主要要讲的就是封装。什么是封装呢:将数据和操作数据的方法进行有机的结合,隐藏对象的属性和实现细节。仅对外公开接口来和对象进行交互。

        封装本质上是对数据的一种管理,就像银行不对我们开放银行内部的处理资金的细节,仅仅对我们开放一个或者多个窗口来与我们用户进行交流,降低了我们的使用成本。封装也是如此。

 5. 类的作用域

        类重新向我们定义了一种全新的作用域,类的所有成员都在类的作用域中,在类体外定义成员需要使用”::“作用域操作符指明成员属于哪个类域。

class Date 
{
public:
	void addDate();
private:
	int _year;
	int _month;
	int _day;
};
void Date::addDate()
{
	cout << "void addDate()";
}

 6. 类的实例化

         类的实例化就是使用类创建对象的过程,而类就相当于一张图纸,实例化就是将这个图纸实现的过程。一个类可以实例化出多个对象,实例化出来的对象占用实际的物理空间,存储类成员变量。

 

7. 类对象模型

7.1 类对象的存储方式

        类实例化的时候只会保存成员变量,成员函数存放在公共的代码段。

         我们也可以通过获取对象的大小来验证一下上面的存储方式。

class Date 
{
public:
	void addDate()
	{}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	cout << sizeof(d1);
}

 输出:

12

        代码中我们可以看出类的大小仅仅是三个int类型变量的大小,所以可以证明存储模型是正确的。并且我们的类的大小也遵从内存对齐规则。 

7.2 类的大小

7.2.1 空类的大小

        当我们定义一个空类的时候,实例化这个类,实例化后的对象的大小不为0,而是1,这一个字节用来占位,表示这个对象确实存在。非空类的大小就需要按照内存对齐的规则进行计算。

class MyClass
{};
int main()
{
	MyClass mc;
	cout << sizeof(mc);
}

输出:

1

 7.2.2 结构体内存对齐规则

         C++中无论是结构体还是类都遵从内存对齐的原则,这里的内存对齐和c语言的结构体内存对齐完全相同,所以不在进行过多的讲解。 

  1. 第一个成员在与结构体偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的对齐数为8
  3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

8. this关键字深入讲解

 8.1 this指针的引出

        在上面内容的叙述中我们得知成员函数是保存在公共代码区的,那我们实例化的对象是怎样准确的在成员函数中调用自己的成员变量的呢?这就是我们要说的this关键字,其实也就是this指针。this指针其实成员函数的第一个隐含参数,当我们实例化的对象调用的这个函数的时候,会自动将自己的地址传进去。

        我们看到的代码和输出:

class Date
{
public:
	void print()
	{
		cout << _year << "年" << _month << "月" << _day << "日";
	}
private:
	int _year = 2023;  //缺省值,用于默认构造时成员变量的默认值,会在后续构造函数中讲到
	int _month = 8;    //暂时不用太过注意
	int _day = 6;
};
int main()
{
	Date d1;
	d1.print();
}

输出:
2023年8月6日

        实际上的代码(编译器处理过的):

 8.2 this指针的特性

  1. this指针的类型:类型* const,即成员函数中,不能给this指针赋值。
  2. 只能在“成员函数”的内部使用
  3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给 this形参。所以对象中不存储this指针。
  4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传 递,不需要用户传递
//相当于下面的代码
class Date
{
public:
	void print(Date* const this)
	{
		cout << this->_year << "年" << this->_month << "月" << this->_day << "日";
	}
private:
	int _year = 2023;  
	int _month = 8;    
	int _day = 6;
};
int main()
{
	Date d1;
	d1.print(&d1);
}

         不过还有一种特殊的情况会使我们调用print函数失败,就是我们传入的对象d1是const类型,如下:

 9.空指针调用成员函数的问题

        这里大家可能就要怀疑了,空指针怎么可能可以调用成员函数呢,答案是当函数里面没有发生对成员变量的解引用操作就可以调用。如下:

        这里的print函数被保存在公共代码区中,并且没有发生任何的空指针访问的行为,所以可以调用成功。

class Date
{
public:
	void print()
	{
		//这里没有在函数体内对成员函数进行操作,
        //而我们的成员函数是统一放在公共代码区的,
        //所以这里也就没有发生任何的空指针行为,所以是可以被调用成功的。
		cout << "void print()" << endl;
	}
private:
	int _year = 2023;
	int _month = 8;
	int _day = 6;
};
int main()
{
	Date* d1 = nullptr;
	d1->print();
}

 输出:

void print()

        而下面的print函数对空指针进行了解引用行为,所以程序就发生了崩溃。

class Date
{
public:
	void print()
	{
		//这里对空指针进行了解引用的操作,
		//引发了空指针的非法访问,所以代码就会直接崩溃
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
		//引发了异常: 读取访问权限冲突。this 是 nullptr。
	}
private:
	int _year = 2023;
	int _month = 8;
	int _day = 6;
};
int main()
{
	Date* d1 = nullptr;
	d1->print();
}

输出:无输出

异常:引发了异常: 读取访问权限冲突。this 是 nullptr。

综上:我们就将和类有关的基础知识说的差不多了,后面我们就要开始讲解类的六大默认成员函数了,将会是一块难啃的骨头,敬请期待。码文不易,记得三连奥。

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

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

相关文章

如何选择适合自己的考试培训系统

随着考试的逐渐增多和竞争的加剧&#xff0c;许多人开始关注考试培训系统&#xff0c;以提高他们的考试成绩。然而&#xff0c;选择适合自己的考试培训系统并不容易&#xff0c;因为市场上有许多不同的培训系统可供选择。 1. 确定目标 在选择培训系统之前&#xff0c;首先要明…

Java并发编程(一)多线程基础概念

概述 多线程技术&#xff1a;基于软件或者硬件实现多个线程并发执行的技术 线程可以理解为轻量级进程&#xff0c;切换开销远远小于进程 在多核CPU的计算机下&#xff0c;使用多线程可以更好的利用计算机资源从而提高计算机利用率和效率来应对现如今的高并发网络环境 并发编程…

无涯教程-Perl - getpriority函数

描述 此函数返回进程(PRIO_PROCESS),进程组(PRIO_PGRP)或用户(PRIO_USER)的当前优先级。 参数WHICH指定要为PRIO_PROCESS,PRIO_PGRP或PRIO_USER之一设置优先级的实体,WHO是要设置的进程ID或用户ID。 WHO的值为0定义了当前流程,流程组或用户。这会在不支持系统getpriority()函…

C++STL简介:提升编程效率与可维护性的利器

目录 引言 一、STL基本概念 二、具体介绍 2.1 容器 2.2 算法 2.2.1 排序&#xff08;Sort&#xff09; 2.2.2 查找&#xff08;Find&#xff09; 2.3.2 复制&#xff08;Copy&#xff09; 2.3 迭代器 三、分析STL 优势&#xff1a; 缺点&#xff1a; 如何学习&#…

《合成孔径雷达成像算法与实现》Figure3.7

代码复现如下&#xff1a; clc clear all close all%参数设置 TBP 100; %时间带宽积 T 10e-6; %脉冲持续时间%参数计算 B TBP/T; …

做BI领域的ChatGPT,思迈特升级一站式ABI平台

8月8日&#xff0c;以「指标驱动 智能决策」为主题&#xff0c;2023 Smartbi V11系列新品发布会在广州丽思卡尔顿酒店开幕。 ​ 后疫情时代&#xff0c;BI发展趋势的观察与应对 在发布会上&#xff0c;思迈特CEO吴华夫在开场致辞中表示&#xff0c;当前大环境背景下&#xf…

行业追踪,2023-08-09

自动复盘 2023-08-09 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

讯飞星火大模型无需代码连接飞书即时消息的方法

1 使用场景 用户联络需求的升级&#xff0c;使智能客服与智能营销迎来飞速增长&#xff0c;客户服务也成为企业经营中非常重要的一环&#xff0c;如何提高客户服务质量和响应速度&#xff0c;一直是企业需要解决的难题。人工智能产品&#xff0c;也正在成为越来越多企业提升业务…

flutter3.0项目集成高得地图

文章目录 1.创建应用:注册高得开发平台 安卓端的设置flutter的集成ios端的设置 先看一下代码运行结果 安卓端真机 ios端真机屏幕录屏 本篇文章demo下载地址 下载后请用xcode修改自己的ios证书真机运行.flutter代码在PG1.dart里面修改 String androidKey “b3392bb7fe532b0eb…

Mac终端利器:Homebrew + iTerm2 + Oh My Zsh 教程

引言 前段时间调整了一下 iTerm2 的环境&#xff0c;感觉比以前好看多了&#xff0c;并且更加高效&#xff0c;这里做一个记录&#xff0c;希望能给大家一些启发。 工具介绍 brew&#xff1a;Mac OS 下强大的包管理工具。iTerm2&#xff1a;iTerm2是 Mac OS 终端的替代品&am…

实现vuex数据持久化处理

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 前言&#xff1a; 方案一 localStorage 介绍 值 示例 JSON.stringify() 介绍 语法 参数 返…

深入JVM - JIT分层编译技术与日志详解

深入JVM - JIT分层编译技术与日志详解 文章目录 深入JVM - JIT分层编译技术与日志详解1. 背景简介2. JIT 编译器2.1. 客户端版本的编译器: C12.2. 服务端版本的编译器: C22.3. Graal JIT 编译器 3. 分层编译技术(Tiered Compilation)3.1. 汇聚两种编译器的优点3.2. 精准优化(Ac…

人工智能、BIM技术、机器学习在智慧工地的应用

人工智能、BIM技术、机器学习在智慧工地的应用 智慧工地云平台是专为建筑施工领域所打造的一体化信息管理平台。通过大数据、云计算、人工智能、BIM、物联网和移动互联网等高科技技术手段&#xff0c;将施工区域各系统数据汇总&#xff0c;建立可视化数字工地。同时&#xff0…

⌈算法进阶⌋图论::并查集——快速理解到熟练运用

目录 一、原理 1. 初始化Init 2. 查询 find 3. 合并 union 二、代码模板 三、练习 1、 990.等式方程的可满足性 &#xff08;中等&#xff09; 2、 1061. 按字典序排列最小的等效字符串 &#xff08;中等&#xff09; 3、账户合并 &#xff08;较难&am…

QFontDialog

QFontDialog QFont字体类使用QFont类QFontDialog类的静态API简单的使用 QFontDialog类是QDialog的子类, 通过这个类我们可以得到一个进行字体属性设置的对话框窗口, 和前边介绍的对话框类一样, 我们只需要调用这个类的静态成员函数就可以得到想要的窗口了。 QFont字体类 关于…

Android自定义侧滑Item

源码地址&#xff1a;https://github.com/LanSeLianMa/CustomizeView/tree/master/cehuaitem 使用方式一&#xff1a;XML布局中直接使用 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com…

python怎么判断变量的数据类型

在编程的世界里&#xff0c;了解各种数据类型是非常重要的。在Python中&#xff0c;有着丰富的数据类型用于存储和处理不同类型的数据。掌握这些数据类型的定义和作用&#xff0c;我们能够更好地在程序中管理和操作数据&#xff0c;提高代码的效率和可读性。 Python中常见的数据…

使用node搭建服务器,前端自己写接口,将vue或react打包后生成的dist目录在本地运行

使用node.jsexpress或者使用node.jspm2搭建服务器&#xff0c;将vue或react打包后生成的dist目录在本地运行 vue项目打包后生成的dist目录如果直接在本地打开index.html,在浏览器中会报错&#xff0c;无法运行起来。 通常我是放到后端搭建的服务上面去运行&#xff0c;当时前端…

pve和openwrt以及我的电脑中网络的关系和互通组网

情况1 一台主机 有4个口&#xff0c;分别eth0,eth1,eth2,eth3 pve有管理口 这个情况下 &#xff0c;没有openwrt 直接电脑和pve管理口连在一起就能进pve管理界面 情况2 假设pve 的管理口味eth0 openwrt中桥接的是eth0 eth1 eth2 那么电脑连接eth3或者pve管理口设置eth3&#xf…