3. C++类和对象

news2024/11/27 18:39:08

一、面向对象程序设计的基本特点

1.1 抽象

  • 指对具体问题(对象)进行概括,抽出一类对象的公共性质并加以描述的过程

  • 数据抽象

    • 描述某类对象的属性或状态,即此类对象与其他类对象的区别
  • 行为抽象

    • 描述某类对象的共同行为或功能特征

      以人为例,对其进行抽象。
      共同属性:姓名、性别、年龄等等,则数据抽象:

      string name, string sex, int age

      共同的行为:吃饭、走路、学习等等,则行为抽象:

      eat(), walk(), study()

1.2 C++面向对象三大特性

  1. 封装将数据和操作数据的函数代码进行有机结合,形成 “ 类 ”,其中的数据和函数都是类的成员
  2. 继承:允许在保存原有类特性的基础上,进行更具体、更详细的说明
  3. 多态:一段程序能处理多种类型对象的能力

二、类和对象的基本概念

2.1 封装

  1. 目的:

  2. 增强安全性和简化编程,使用者不需要具体了解实现细节,只需要通过外部接口,以特定的权限进行访问,使用类的成员

  3. 意义:

    1. 将属性和行为作为一个整体
    2. 将属性和行为加以权限控制
  4. 语法:

    class ClassName {
        访问权限:
            属性
            行为
    }
    

2.2 类和对象

  • 类(class)
    • 对逻辑上相关的函数和数据的封装,是对问题的抽象描述
    • 在面向对象程序设计中,程序模块是由类构成的
  • 对象(object)
    • 是具有class类型的变量
    • C++认为万事万物皆为对象对象具有属性行为
    • 具有相同性质的对象,可以抽象为类
      • 例如,人属于人类,人作为对象,属性包括姓名、性别、年龄等,行为包括吃饭、走路、学习等
      • 类中的属性和行为,统称为成员
        • 属性:成员属性,成员变量
        • 行为:成员函数,成员方法
    • 创建对象的过程叫实例化,新创建的对象叫实例(instance)

2.3 类的定义

2.3.1 语法

// 类名称通常将首字母写成大写
class 类名{
public:
    公有成员(外部接口) // 任何外部函数都可访问
private:
    私有成员		   // 只允许本类中的函数访问
protected:
    保护型成员		  // 与继承有关
}

// 实例化一个对象
类名	对象名;

// 访问数据成员
对象名.数据成员名

// 调用函数成员
对象名.函数成员名(参数表)

示例:

image-20220605003216489
// 封装一个圆类,求圆的面积和周长
class Circle{
public:
    // 属性:半径
    int radius;
    // 行为:获取圆面积;获取圆周长
    double findArea();
    double findPerimeter();
};

int main(){
    Circle c;
    c.radius = 10;
    
    std::cout << "圆的面积:" << c.findArea() << std::endl;
    std::cout << "圆的周长:" << c.findPerimeter() << std::endl;
}

2.3.2 成员访问权限

  • public、protected和private是访问权限修饰符
    • 被public修饰的属性和函数可以在类内部与类外部被访问
    • 被protected和private修饰的属性和函数只能在类内部被访问
  • 成员函数可以访问本类中任何成员。一般的做法是将需要被外界调用的成员函数指定为public,他们是类的对外接口
  • 有的函数并不是准备为外界调用的,而是为本类中的成员函数所调用的,就应该将它们指定为private
  • 一般将属性定义为私有,行为定义为公有
  • struct和class的区别:默认的访问权限不同
    • struct 默认权限为公共
    • class 默认权限为私有

示例:

class Clock{
public:
    void setTime(int newH, int newM, int newS);
    void showTime();
private:
    int hour, minute, second;    
}

2.3.3 类的成员函数

  • 描述类的行为,对封装的数据进行操作的方法

  • 函数的原型声明要写在类体中,函数的具体实现写在类定义外

  • 类成员函数的默认值,一定要写在类定义中

  • 语法:

    返回值类型	类名::函数成员名(参数表){
        
        函数体
    
    }
    

    示例:

    #include <iostream>
    using namespace std;
    class Clock {
    public:
        void setTime(int newH = 0, int newM = 0, int newS = 0);
        void showTime();
    private:
        int hour, minute, second;    
    };
    
    // 类成员函数setTime
    void Clock::setTime(int newH, int newM, int newS) {
        hour = newH;
        minute = newM;
        second = newS;
    }
    // 类成员函数showTime
    void Clock::showTime() {
        cout << hour << ":" << minute << ":" << second;
    }
    
    int main() {
        Clock myClock;	// 定义对象
        myClock.setTime(8, 30, 30);	// 通过“.”操作符实现对象成员函数的访问
        myClock.showTime();
        return 0;
    }
    

2.4 多文件编写代码

2.4.1 多文件结构

通常一个项目至少划分为3个文件:

  • 类定义文件(*.h文件)
    • 写类的声明,包括了所有函数的函数头
  • 类实现文件(*.cpp文件)
    • 写类的定义
    • 注意要引用类定义文件,#include *.h
    • 定义成员函数时函数名称前要加上类名:类名::函数,例如:Clock::setTime
  • 类使用文件(*.cpp,主函数文件)
    • 创建类对象并进行调用
    • 注意要引用类定义文件,#include *.h

更为复杂的程序,可以将每一个类都用单独的定义和实现文件

image-20220607093523738

2.4.2 例子:点和圆的关系

image-20230509102226707
  • 所有代码在同一个源文件内

    # include <iostream>
    using namespace std;
    
    class Point { //点类
    public:
        void setX(int x) { m_X = x; } //设置x
        int getX() { return m_X; }    //获取x
        void setY(int y) { m_Y = y; } //设置y
        int getY() { return m_Y; }    //获取y
    private:
        int m_X;
        int m_Y;       
    };
    
    class Circle { //圆类
    public: 
        void setR(int r) { m_R = r; }				        //设置半径    
        int getR(){ return m_R; }						   //获取半径    
        void setCenter(Point center){ m_Center = center; }	 //设置圆心   
        Point getCenter(){ return m_Center; } 				//获取圆心   
    private:
        int m_R;    //半径
       
        //
        //在类中可以让另一个类作为本类的成员
        //
        Point m_Center;  //圆心      
    };
    
    //判断点和圆的关系
    void isInCircle(Circle &c, Point &p){
        //计算两点之间距离平方
        int distance = (c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
                       (c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
        //计算半径的平方
        int rDistance = c.getR() * c.getR();
        
       //判断关系
       if(distance == rDistance){
           cout << "点在圆上" << endl; 
       }else if(distance > rDistance){
           cout << "点在圆外" << endl;
       }else{
           cout << "点在圆内" << endl;
       }               
    }
    
    int main(){
        //创建圆
        Circle c;
        c.setR(10);
        Point center;
        center.setX(10);
        center.setY(0);
        c.setCenter(center);
        //创建点
        Point p;
        p.setX(10);
        p.setY(10);
        //判断关系
        isInCircle(c, p);
    }
    
  • 多文件编写

    • 点类头文件point.h(写点类的类声明)

      # pragma once
      # include <iostream>
      using namespace std;
      
      class Point { //点类
      public:
          void setX(int x); //设置x
          int getX();       //获取x
          void setY(int y); //设置y
          int getY();       //获取y
      private:
          int m_X;
          int m_Y;       
      };
      
    • 点类源文件point.cpp(写点类的类定义)

      # include "point.h"
      
      //设置x
      void Point::setX(int x) { 
          m_X = x; 
      } 
      //获取x
      int Point::getX() { 
          return m_X; 
      }    
      //设置y
      void Point::setY(int y) { 
          m_Y = y; 
      } 
      //获取y
      int Point::getY() { 
          return m_Y; 
      }    
      
    • 圆类头文件circle.h(写圆类的类声明)

      # pragma once
      # include <iostream>
      using namespace std;
      
      class Circle { //圆类
      public: 
          void setR(int r) { m_R = r; }				        //设置半径    
          int getR(){ return m_R; }						   //获取半径    
          void setCenter(Point center){ m_Center = center; }	 //设置圆心   
          Point getCenter(){ return m_Center; } 				//获取圆心   
      private:
          int m_R;    //半径
          Point m_Center;  //圆心      
      };
      
    • 圆类源文件circle.cpp(写圆类的类定义)

      # include "circle.h"
      
      //设置半径
      void Circle::setR(int r){
          m_R = r;
      }
      //获取半径
      int Circle::getR(){
         return m_R;
      }
      //设置圆心
      void Circle::setCenter(Point center){
          m_Center = center;
      }
      //获取圆心
      Point Circle::getCenter(){
          return m_Center;
      }
      
    • 主函数main.cpp(调用类)

      # include <iostream>
      # include "circle.h"
      # include "point.h"
      using namespace std;
      
      //判断点和圆的关系
      void isInCircle(Circle &c, Point &p){
         //计算两点之间距离平方
         int distance = (c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
                         (c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
         //计算半径的平方
         int rDistance = c.getR() * c.getR(); 
         //判断关系
         if(distance == rDistance){
             cout << "点在圆上" << endl; 
         }else if(distance > rDistance){
             cout << "点在圆外" << endl;
         }else{
             cout << "点在圆内" << endl;
         }               
      }
      
      int main(){
          //创建圆
          Circle c;
          c.setR(10);
          Point center;
          center.setX(10);
          center.setY(0);
          c.setCenter(center);
          //创建点
          Point p;
          p.setX(10);
          p.setY(10);
          //判断关系
          isInCircle(c, p);
      }
      

三、结构体

3.1 结构体和类的区别

  • 二者基本没有区别,唯一的区别就是struct的成员的访问控制默认是pubilc,而class默认是private
  • C++中结构体存在的唯一原因是想要维持与C之间的兼容性

3.2 定义和使用

  • 结构体struct是用户自定义的数据类型,允许用户存储不同的数据类型
  • 语法:struct 结构体名 { 结构体成员列表 };
  • 结构体变量创建方式:
    • struct 结构体名 变量名
    • struct 结构体名 变量名 = { 成员1值 , 成员2值…}
    • 定义结构体时顺便创建变量
  • 结构体变量利用操作符 “ . ” 访问成员
//结构体定义
struct student {
	//成员列表
	string name;  //姓名
	int age;      //年龄
	int score;    //分数
} stu3; //结构体变量创建方式3 

int main() {
	//结构体变量创建方式1
	struct student stu1; //struct 关键字可以省略

	stu1.name = "张三";
	stu1.age = 18;
	stu1.score = 100;
	
	cout << "姓名:" << stu1.name << " 年龄:" << stu1.age  << " 分数:" << stu1.score << endl;

	//结构体变量创建方式2
	struct student stu2 = { "李四", 19, 60 };
	cout << "姓名:" << stu2.name << " 年龄:" << stu2.age  << " 分数:" << stu2.score << endl;
	
    //结构体变量创建方式3, 定义结构体时顺便创建变量stu3
	stu3.name = "王五";
	stu3.age = 18;
	stu3.score = 80;
	cout << "姓名:" << stu3.name << " 年龄:" << stu3.age  << " 分数:" << stu3.score << endl;

	return 0;
}

3.3 结构体数组

  • 将自定义的结构体放入到数组中方便维护
  • 语法:struct 结构体名 数组名[元素个数] = { {} , {} , ... {} };
//结构体定义
struct student {
	string name;  //姓名
	int age;      //年龄
	int score;    //分数
};

int main() {
	//结构体数组
	struct student arr[3] = {
		{"张三", 18, 80 },
		{"李四", 19, 60 },
		{"王五", 20, 70 }
	};

	for (int i = 0; i < 3; i++) {
		cout << "姓名:" << arr[i].name << " 年龄:" << arr[i].age << " 分数:" << arr[i].score << endl;
	}

	return 0;
}

3.4 结构体指针

  • 通过指针访问结构体中的成员
  • 利用操作符 -> 可以通过结构体指针访问结构体属性
struct student {
	string name;  //姓名
	int age;      //年龄
	int score;    //分数
};

int main() {
	struct student stu = { "张三", 18, 100 };
	struct student * p = &stu;
	p->score = 80; //指针通过 -> 操作符可以访问成员
	cout << "姓名:" << p->name << " 年龄:" << p->age << " 分数:" << p->score << endl;

	return 0;
}

3.5 结构体嵌套

//学生结构体定义
struct student {
	string name;  //姓名
	int age;      //年龄
	int score;    //分数
};

//教师结构体定义
struct teacher {
	int id; 			//职工编号
	string name;  		//教师姓名
	int age;   			//教师年龄
	struct student stu;  //子结构体 学生
};

int main() {
	struct teacher t1;
	t1.id = 10000;
	t1.name = "老王";
	t1.age = 40;
    
	t1.stu.name = "张三";
	t1.stu.age = 18;
	t1.stu.score = 100;
    
	cout << "教师 职工编号: " << t1.id << " 姓名: " << t1.name << " 年龄: " << t1.age << endl;
	cout << "辅导学员 姓名: " << t1.stu.name << " 年龄:" << t1.stu.age << " 考试分数: " << t1.stu.score << endl;
    
	return 0;
}

3.6 结构体做函数参数

  • 将结构体作为参数向函数中传递
  • 值传递和地址传递两种方式
//学生结构体定义
struct student {
	string name;  //姓名
	int age;      //年龄
	int score;    //分数
};

//值传递
void printStudent(student stu) {
	stu.age = 28;
	cout << "子函数中 姓名:" << stu.name << " 年龄: " << stu.age  << " 分数:" << stu.score << endl;
}

//地址传递
void printStudent2(student *stu) {
	stu->age = 28;
	cout << "子函数中 姓名:" << stu->name << " 年龄: " << stu->age  << " 分数:" << stu->score << endl;
}

int main() {
	student stu = { "张三",18,100};
	//值传递
	printStudent(stu);
	cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;

	//地址传递
	printStudent2(&stu);
	cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age  << " 分数:" << stu.score << endl;

	return 0;
}

3.7 const

  • 用const来防止误操作
struct student {
	string name;  //姓名
	int age;      //年龄
	int score;    //分数
};

//const使用场景
//加const防止函数体中的误操作
void printStudent(const student *stu) {
	//stu->age = 100; //操作失败,因为加了const修饰
	cout << "姓名:" << stu->name << " 年龄:" << stu->age << " 分数:" << stu->score << endl;
}

int main() {
	student stu = { "张三",18,100 };
	printStudent(&stu);
	return 0;
}

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

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

相关文章

IP核之fifo

一.FIFO简介 FIFO (First In First Out&#xff0c;即先入先出&#xff09;&#xff0c;是一种数据缓冲器&#xff0c;用来实现数据先入先出的读写方式。 二&#xff0c;FIFO实现原理 FIFO是采用一种先入先出的实现原理 就如图按照D1到D10的顺序输入那么读取的时候也是按照D…

web浏览器打开本地exe应用

一、如何使web浏览器打开本地exe应用&#xff1f; 浏览器打开本地exe程序我们可以使用ActiveXObject方法&#xff0c;但是只支持IE&#xff0c;谷歌、火狐等浏览器并不支持此操作。 那问题来了&#xff0c;我们又该如何操作&#xff1f; 经过本博主的不断学习探索终于找到了一…

多语言一键铺货跨境电商平台快速开发(java开源)

要搭建一个多语言一键铺货跨境电商平台&#xff0c;可以参考以下步骤&#xff1a; 1. 确定需求&#xff1a;首先&#xff0c;明确平台的功能需求&#xff0c;包括多语言支持、一键铺货功能、跨境支付等。 2. 选择适合的开源项目&#xff1a;选择一个适合的Java开源电商平台项…

Unity 编辑器资源导入处理函数 OnPreprocessAudio :深入解析与实用案例

Unity 编辑器资源导入处理函数 OnPreprocessAudio 用法 点击封面跳转下载页面 简介 在 Unity 中&#xff0c;资源导入是一个非常重要的环节&#xff0c;它决定了资源在项目中的使用方式和效果。Unity 提供了一系列的资源导入处理函数&#xff0c;其中之一就是 OnPreprocessAud…

Crond计划任务的简单使用

目录 前言 一、一次性任务at 二、crond周期性任务 总结 前言 crond是Linux系统中的一个守护进程&#xff0c;负责定期执行预设的任务&#xff0c;也称为计划任务。它可以根据用户的需求&#xff0c;在指定的时间、日期或周期性地执行特定的命令或本crond的用是自动化和定时执行…

JavaWeb_LeadNews_Day5-文章定时发布

JavaWeb_LeadNews_Day5-文章定时发布 延时服务概述DelayQueueRabbitMQ(常用)Redis(常用) redis延迟服务实现思路总思路添加任务取消任务拉取任务未来数据定时刷新redis解决集群抢占 具体实现乐观锁docker运行redis项目集成redis添加任务取消任务拉取任务未来数据定时刷新redis解…

Jmeter入门之digest函数 jmeter字符串连接与登录串加密应用

登录请求中加密串是由多个子串连接&#xff0c;再加密之后传输。 参数连接&#xff1a;${var1}${var2}${var3} 加密函数&#xff1a;__digest &#xff08;函数助手里如果没有该函数&#xff0c;请下载最新版本的jmeter5.0&#xff09; 函数助手&#xff1a;Options > …

【Hystrix技术指南】(1)基本使用和配置说明

这世间许多事物皆因相信而存在&#xff0c;所以人们亲手捏出了泥菩萨&#xff0c;却选择坚定的去信仰它。 分布式系统的规模和复杂度不断增加&#xff0c;随着而来的是对分布式系统可用性的要求越来越高。在各种高可用设计模式中&#xff0c;【熔断、隔离、降级、限流】是经常被…

wordpress日主题Ripro9.0最新二开修正源码下载+美化包和插件

日主题Ripro9.0最新二开升级修正源码美化包和插件&#xff0c;RiPro9.0的二开版本新模板&#xff0c;包含2个美化包和全屏水印以及防复制插件。 模板和美化包路径:\wp-content\themes 插件路径&#xff1a;\wp-content\plugins&#xff0c;有兴趣的自行去体验吧

AOP-AspectJ 切面技术及使用MethodInterceptor实现切面

目录 一、简介 二、什么是AspectJ AOP 思想概述 AOP 实现方式 AOP 特性概念 切点指示器 通知类型 三、实现AOP的方式 四、配置说明 自定义注解作为切点 NeedCut MyAop GirlController 继承MethodInterceptor实现切面 MyMethodInterceptor AopConfig NeedCut 注解…

如何将安卓 Gradle 模块打包发布到本地 Maven 仓库

文章目录 具体流程 笔者的运行环境&#xff1a; Android Studio Flamingo | 2022.2.1 Android SDK 33 Gradle 8.0.1 JDK 17 Android 的 Gradle 项目与一般的 Gradle 项目是不同的&#xff0c;因此对将 Gradle 模块打包发布到本地 Maven 仓库来说&#xff0c;对普通 Gradle …

Python 模块 locust 性能测试

简介 locust 是 Python 的一个开源的负载测试工具&#xff0c;用于测试网络应用程序的性能和可伸缩性。它使用Python编写&#xff0c;并提供了一个简单易用的语法来定义和执行负载测试。locust模块允许用户模拟大量并发用户并观察系统在高负载下的响应情况。 目录 1. 基本用法…

vue中transition动画的使用

1.vue文件 说明&#xff1a;加name属性 <transition name"sort"><div class"sort" v-show"show"><div class"all-sort-list2" click"goSearch"><div class"item bo" v-for"(item1, in…

图像膨胀+滤波达到边缘外扩模糊效果

有一个扯淡需求, 根据某些格网值渲染对应的颜色, 我们做的实现方案是按照色代码渐变做颜色映射, 但是某些厂家不顾结果正确性与否, 应是为了好看做的好看, 将边界膨胀模糊, 一个非风场,力场类似场数据做了一个类似场的渲染效果, 也不知道说啥好, 例如原始图渲染如下 经过一系列…

初识http协议,简单实现浏览器和服务器通信

文章目录 认识urlhttp协议格式通信代码验证细节Util.hppprotocol.hppServer.hppServer.cc 结果分析 认识url 平时俗称的 “网址” 其实就是说的 URL&#xff0c;例如在百度上搜索一个C 可以看到这段网址前面有个 https 那么这个就代表着使用的是https协议&#xff0c;现在都是…

0807hw

1. 2. (1)a100,b10; a10,b100;//值传递 (2)*a100,*b10; a100,b10;//地址传递 (3)*a100,*b10; a10,b100;

深入探索 Splashtop Enterprise 的潜力

在当今高度技术化的环境中&#xff0c;远程访问解决方案已成为无数组织的支柱。远程访问解决方案缩短了员工与工作之间的地理差距&#xff0c;提高了工作的效率和灵活性&#xff0c;促进形成了无缝的工作体验。在众多远程访问解决方案中&#xff0c;Splashtop Enterprise 作为远…

FFmpeg中AVIOContext的使用

通过FFmpeg对视频进行编解码时&#xff0c;如果输入文件存在本机或通过USB摄像头、笔记本内置摄像头获取数据时&#xff0c;可通过avformat_open_input接口中的第二个参数直接指定即可。但如果待处理的视频数据存在于内存块中时&#xff0c;该如何指定&#xff0c;可通过FFmpeg…

Linux初识网络基础

目录 网络发展 认识“协议 ” 网络协议 OSI七层模型&#xff1a; TCP/IP五层&#xff08;或四层&#xff09;模型 网络传输基本流程 网络传输流程图&#xff1a; 数据包封装和封用 网络中的地址 认识IP地址&#xff1a; 认识MAC地址&#xff1a; 网络发展 1.独立…

JAVA实用工具: 改良版雪花算法-分布式唯一ID神器

Seata内置了一个分布式UUID生成器,用于辅助生成全局事务ID和分支事务ID。具体如下特点: 高性能全局唯一趋势递增这个分布式UUID生成器是基于雪花算法进行改良的,本文针对改良的方法、目的等进行总结 改良点 改良版雪花算法的实现原理参考如下: Seata基于改良版雪花算法的…