C++ 类与对象Oop

类与对象Oop

  • 一、类:用户定义的数据类型,用于封装数据和方法
    • 1.1 对比结构体
      • 警告-->主要目的:初始化
    • 1.2 定义类的过程并定义一个对象
      • 1.2.1 定义类
        • 例子
      • 1.2.2 定义一个对象
      • 1.2.3 注意事项+例子
      • 1.2.4 分成头文件和源文件的方式
        • (0)注意事项
        • (1)Point.h
        • (2) Point.cpp
        • (3) Circle.h
        • (4) Circle.cpp
        • (5)main.cpp
    • 1.3 构造函数和析构函数
      • 1.3.1 构造函数: 类名(){}
      • 1.3.2 析构函数: ~类名(){}
      • 1.3.3 示例
        • (1)这两种方式都可以创建`Person`对象,但它们的作用域和生命周期是不同的。
        • (2)匿名对象

同Java一样,C++具备这面向对象的概念。我们也可以和java对比着学习,发现他们的不同:
此处是我的java博客的链接:
我在VScode学Java类与对象(Java的类与对象、this关键字)

先了解下面的概念

过程性编程(Procedural programming)是一种编程范式,它将程序分解为一系列的步骤或过程。这些过程按照顺序执行,通常涉及函数和指令的调用。过程性编程强调程序的执行过程,以及数据和功能之间的分离。

面向对象编程(Object-oriented programming)是另一种编程范式,它将数据和功能组合成对象。对象可以包含数据(称为属性或成员变量)和操作数据的方法(称为方法或成员函数)。面向对象编程强调数据和功能的封装,继承和多态性。

一、类:用户定义的数据类型,用于封装数据和方法

类是一种用户定义的数据类型,用于封装数据和方法。
它可以包含成员变量(数据)和成员函数(方法),并且可以通过实例化创建对象。
提供了一种组织和管理代码的方式,以及实现数据抽象和封装的能力。

在面向对象编程中,类的定义通常包括类声明和类方法定义两部分。

类声明描述了类的数据部分,通常以数据成员的方式描述。同时,它也描述了类的公有接口,即类的方法或成员函数。这部分提供了类的蓝图,定义了类的结构和公有接口。

类方法定义描述了如何实现类的成员函数,即方法的具体实现细节。这部分提供了类成员函数的具体实现,包括方法的功能和操作。

#include <iostream>using namespace std;// Class declaration
class MyClass {
private:int data; // Data memberpublic:void setData(int value); // Member function declarationint getData(); // Member function declaration
};// Class method definition
void MyClass::setData(int value) {data = value;
}int MyClass::getData() {return data;
}int main() {MyClass obj;obj.setData(42);cout << "Data: " << obj.getData() << endl;return 0;
}

1.1 对比结构体

C++中的结构体(struct)和类(class)都可以用来定义自定义数据类型。它们的主要区别在于默认的访问权限和成员函数。结构体的默认访问权限是公共的(public),而类的默认访问权限是私有的(private)。
此外,类可以包含成员函数和构造函数,而结构体不能包含成员函数,但可以包含构造函数。在实际使用中,结构体通常用于简单的数据聚合,而类用于更复杂的数据抽象和封装。

结构体示例
// 结构体示例
#include <iostream>
using namespace std;struct Person {string name;int age=123;
};int main() {Person person1;person1.name = "Alice";person1.age = 25;cout << "Name: " << person1.name << ", Age: " << person1.age << endl;return 0;
}
类示例

#include <iostream>
using namespace std;class Person {
public:string name;int age;float score;
};int main() {Person person1;person1.name = "Bob";person1.age = 30;person1.score = 89.5;cout << "Name: " << person1.name << ", Age: " << person1.age <<"score" <<person1.score<<endl;return 0;
}

警告–>主要目的:初始化

Clang-Tidy 提示 “Constructor does not initialize these fields: age” 是因为在代码中没有显式地在构造函数中初始化类的成员变量 age。而对于 name,因为它是一个 std::string 类型的成员变量,它有一个默认的构造函数,因此即使没有显式初始化,它也会被默认初始化为空字符串。

所以写成:

class Person {
public:string name;int age{};float score{};
};

1.2 定义类的过程并定义一个对象

1.2.1 定义类

class MyClass {// class members and methods go here
};

定义一个类的过程就是使用关键字class后面跟着类名,然后在大括号内定义类的成员变量和方法。明确我们需要的成员属性,在给定我们需要方法使得类更佳完整。

例子
class Cube {
private:int L, W, H;
public:
//    setter 和 gettervoid setL(int l) {L = l;}int getL() const {return L;}void setW(int w) {W = w;}int getW() const {return W;}void setH(int h) {H = h;}int getH() const {return H;}//    表面积int area() const {return 2 * (L * W + L * H + W * H);}//    体积int volume() const {return L * W * H;}
}

1.2.2 定义一个对象

//    在C++中
Cube c{};

// 使用大括号初始化语法对对象进行值初始化。这确保了对象的所有成员变量都被初始化为其默认值,
// 即int类型的成员变量会被初始化为0。
// 这种初始化方式在C++11标准中引入,它提供了更加一致和可靠的初始化语法,尤其是在涉及到类类型的初始化时。

//    在C++中,使用*操作符可以用来解引用指针。在你提供的代码中,Cube cube = *new Cube();

// 在C++中,使用*操作符可以用来解引用指针。在你提供的代码中,
// *new Cube()创建了一个新的Cube对象,并返回指向该对象的指针。
// 然后,*操作符被用来解引用这个指针,以便将指针指向的对象赋值给cube变量。
//简而言之,new Cube()创建了一个新的Cube对象,并操作符用来解引用指针,以便将指针指向的对象赋值给cube变量。

在这里插入图片描述

1.2.3 注意事项+例子

在C++中定义类时需要注意以下几点:

  1. 类的成员默认是私有的,需要使用public、protected或者private关键字来指定访问权限。
  2. 类的成员函数可以在类内部定义,也可以在类外部定义。
  3. 类的成员变量和方法可以通过对象的实例来访问。
// 2023/11/13日创建
#include <iostream>using namespace std;//PointClass
class Point {
private:// x,y坐标int X;int Y;
public:void setX(int x) { // 设置X坐标X = x;}int getX() { // 获取X坐标return X;}void setY(int y) { // 设置Y坐标Y = y;}int getY() { // 获取Y坐标return Y;}
};//CircleClass
class Circle {
private:int C_R; // 圆的半径Point C_Center; // 圆心坐标
public:void setC_R(int r) { // 设置圆的半径C_R = r;}int getC_R() { // 获取圆的半径return C_R;}void setC_Center(Point p) { // 设置圆心坐标C_Center = p;}Point getC_Center() { // 获取圆心坐标return C_Center;}bool isPointInside(Point p) { // 判断点是否在圆内部int dx = p.getX() - C_Center.getX();int dy = p.getY() - C_Center.getY();int distanceSquared = dx * dx + dy * dy;int radiusSquared = C_R * C_R;return distanceSquared <= radiusSquared;}
};int main() {// 创建Point对象Point p;p.setX(3); // 设置X坐标为3p.setY(4); // 设置Y坐标为4cout << "Point坐标: (" << p.getX() << ", " << p.getY() << ")" << endl;// 创建Circle对象Circle c;c.setC_R(5); // 设置圆的半径为5c.setC_Center(p); // 设置圆心坐标为Point对象pcout << "Circle半径: " << c.getC_R() << endl;cout << "Circle圆心坐标: (" << c.getC_Center().getX() << ", " << c.getC_Center().getY() << ")" << endl;// 判断点是否在圆内部Point testPoint;testPoint.setX(2);testPoint.setY(3);if (c.isPointInside(testPoint)) {cout << "点在圆内部" << endl;} else {cout << "点不在圆内部" << endl;}return 0;
}

在这里插入图片描述

1.2.4 分成头文件和源文件的方式

(0)注意事项

#ifndef和#define是C/C++中的预处理指令,用于防止头文件被多次包含。

#ifndef <标识>
#define <标识>
...
#endif

当头文件被包含到多个源文件中时,防止多次定义同一个标识符。如果标识符已经被定义过,则#ifndef和#define之间的代码会被忽略,直到#endif。

这样可以避免由于重复包含头文件而导致的重复定义错误。

(1)Point.h
// Point.h
#ifndef POINT_H
#define POINT_Hclass Point {
private:int X;int Y;
public:void setX(int x);int getX();void setY(int y);int getY();
};#endif
(2) Point.cpp
// Point.cpp
#include "Point.h"void Point::setX(int x) {X = x;
}int Point::getX() {return X;
}void Point::setY(int y) {Y = y;
}int Point::getY() {return Y;
}
(3) Circle.h
// Circle.h
#ifndef CIRCLE_H
#define CIRCLE_H
#include "Point.h"class Circle {
private:int C_R;Point C_Center;
public:void setC_R(int r);int getC_R();void setC_Center(Point p);Point getC_Center();bool isPointInside(Point p);
};#endif
(4) Circle.cpp
// Circle.cpp
#include "Circle.h"void Circle::setC_R(int r) {C_R = r;
}int Circle::getC_R() {return C_R;
}void Circle::setC_Center(Point p) {C_Center = p;
}Point Circle::getC_Center() {return C_Center;
}bool Circle::isPointInside(Point p) {int dx = p.getX() - C_Center.getX();int dy = p.getY() - C_Center.getY();int distanceSquared = dx * dx + dy * dy;int radiusSquared = C_R * C_R;return distanceSquared <= radiusSquared;
}
(5)main.cpp
// main.cpp
#include <iostream>
#include "Point.h"
#include "Circle.h"using namespace std;int main() {Point p;p.setX(3);p.setY(4);cout << "Point coordinates: (" << p.getX() << ", " << p.getY() << ")" << endl;Circle c;c.setC_R(5);c.setC_Center(p);cout << "Circle radius: " << c.getC_R() << endl;cout << "Circle center coordinates: (" << c.getC_Center().getX() << ", " << c.getC_Center().getY() << ")" << endl;Point testPoint;testPoint.setX(2);testPoint.setY(3);if (c.isPointInside(testPoint)) {cout << "Point is inside the circle" << endl;} else {cout << "Point is not inside the circle" << endl;}return 0;
}

1.3 构造函数和析构函数

对象的初始化和清除是C++中两个非常重要的操作,它们分别对应于构造函数和析构函数。

构造函数:主要作用是在创建对象是为对象的成员赋值,构造函数由编辑器自动调用,无需手动调用

构造函数用于对象的初始化,主要作用是在创建对象时为对象的成员赋值。构造函数的名称与类名相同,没有返回类型,可以有参数。当对象被创建时,构造函数会自动调用,无需手动调用。

析构函数:主要作用是在于对象销毁前系统自动调用,执行一些清除工作

析构函数用于对象的清理,主要作用是在对象销毁前执行一些清除工作,如释放动态分配的内存、关闭文件等。析构函数的名称是在类名前加上波浪号(~),没有返回类型,不接受任何参数。当对象被销毁时(例如超出作用域、delete操作符被调用),析构函数会自动调用,无需手动调用。

如果我们自己不提供构造函数或析构函数,编译器会自动生成默认的构造函数和析构函数,这些默认的函数会执行空实现。但是在某些情况下,我们可能需要自定义构造函数和析构函数来完成特定的初始化和清理工作。

1.3.1 构造函数: 类名(){}

构造函数的特点包括:

  1. 没有返回值也不写void。
  2. 构造函数的名称与类名相同。
  3. 构造函数可以有参数,因此可以发生重载。
  4. 程序在创建对象时会自动调用构造函数,无需手动调用,且只会调用一次。

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

析构函数的特点包括:

  1. 析构函数的名称是在类名前加上波浪号(),例如ClassName。
  2. 析构函数没有返回类型,也不接受任何参数。
  3. 析构函数在对象被销毁时自动调用,用于执行对象的清理工作,如释放资源、关闭文件等。
  4. 如果用户没有显式定义析构函数,编译器会提供一个默认的空实现的析构函数。
  5. 如果类中有动态分配的资源(如使用new关键字分配的内存),通常需要在析构函数中释放这些资源,以避免内存泄漏。
  6. 每个类只能有一个析构函数,析构函数不可以有参数,因此不可以发生重载

1.3.3 示例

class Person {
public:
//    1.构造函数
/*没有返回值也不写void、和类名相同、可以有参数,因此可以发生重载*/Person() {cout << "Person()空参构造的调用" << endl;}
//     2. 析构函数:主要作用是在于对象销毁前系统自动调用,执行一些清除工作
/* 没有返回值也不写void、函数名称与类名相同,在名称前加上符号~、不可以有参数,因此不可以发生重载*/~Person() {cout << "~Person()析构构造的调用" << endl;}};//构造和析构都是必须实现的,如果不成,编译器会给一个空实现
void test() {Person p;
/*栈上的数据,test执行完毕后,释放该对象*/
}int main() {
// 公共作用域下
// 2.构造函数用外部函数调用test();
//或者这样的内部直接用方式
//Person();//如果写在main函数中,那么main函数执行完毕,对象就释放了Person s;system("pause");}

在这里插入图片描述

//构造和析构都是必须实现的,如果不成,编译器会给一个空实现
void test() {Person p;
/*栈上的数据,test执行完毕后,释放该对象*/
}
(1)这两种方式都可以创建Person对象,但它们的作用域和生命周期是不同的。
  1. test();:在test函数中创建了一个Person对象。这个对象是test函数的局部变量,所以它的作用域仅限于test函数。当test函数执行完毕后,这个对象就会被销毁,触发析构函数。

  2. Person();:这是一个匿名对象,它在创建后会立即被销毁。因为它没有名称,所以不能在后续的代码中引用它。这种方式通常用于临时对象的创建,或者作为函数参数。

这两种方式都可以创建对象,但是根据你的需求和对象的使用方式,你可能会选择其中一种。例如,如果你需要在函数中使用一个对象,然后在函数结束时自动销毁它,你可以在函数中创建对象。如果你只需要一个临时对象,你可以创建一个匿名对象。

(2)匿名对象

Person();:这行代码创建了一个匿名对象。这个匿名对象在创建后会立即被销毁,因为它没有名称,所以不能在后续的代码中引用它。这就是匿名对象的生命周期。

Person p =Person();:这行代码首先创建了一个匿名对象,然后通过拷贝构造函数将这个匿名对象的内容复制给了p对象,然后匿名对象被销毁。这样,p对象就拥有了匿名对象的数据,而且p对象的生命周期会持续到它离开其作用域。

这两种方式都可以创建对象,但是根据你的需求和对象的使用方式,你可能会选择其中一种。例如,如果你只需要一个临时对象,你可以创建一个匿名对象。如果你需要一个持久的对象,你可以创建一个具名对象。

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

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

相关文章

Niushop 开源微信商城源码+小程序源码 v5.1.7/支持二开/支持PC、手机、小程序和APP电商源码

源码介绍&#xff1a; Niushop 开源微信商城源码 v5.1.7&#xff0c;它是小程序源码&#xff0c;支持二次开发&#xff0c;同时支持PC、手机、小程序和APP多端电商。 Niushop系统是一款基于ThinkPHP6开发的全面完善的电商解决方案。该系统具备完善的商品管理机制&#xff0c;…

目标检测中的数据增强

整个代码参考:bubbliiiing/object-detection-augmentation。 random_data.py import cv2 import numpy as np from PIL import Image, ImageDrawdef rand(a=0, b=1):return np.random.rand()*(b-a) + adef get_random_data(annotation_line, input_shape, jitter=.3, hue=.1…

中仕公考:国考进面后资格复审需要准备什么?

参加国考面试的考生在资格审核阶段需要准备以下材料&#xff1a; 1、本人身份证、学生证或工作证复印件。 2、公共科目笔试准考证复印件。 3、考试报名登记表。 4、本(专)科、研究生各阶段学历、学位证书(应届毕业生没有可以暂时不提供)。 5、报名资料上填写的各类证书材料…

数据结构实验6:图的应用

目录 一、实验目的 1. 邻接矩阵 2. 邻接矩阵表示图的结构定义 3. 图的初始化 4. 边的添加 5. 边的删除 6. Dijkstra算法 三、实验内容 实验内容 代码 截图 分析 一、实验目的 1&#xff0e;掌握图的邻接矩阵的存储定义&#xff1b; 2&#xff0e;掌握图的最短路径…

网络安全产品之认识WEB应用防火墙

随着B/S架构的广泛应用&#xff0c;Web应用的功能越来越丰富&#xff0c;蕴含着越来越有价值的信息&#xff0c;应用程序漏洞被恶意利用的可能性越来越大&#xff0c;因此成为了黑客主要的攻击目标。传统防火墙无法解析HTTP应用层的细节&#xff0c;对规则的过滤过于死板&#…

VsCode重新安装需要配机的ESLint和 Prettier - Code formatter 配置

新电脑安装完Vscode后&#xff0c;需要装几个插件&#xff0c;这里记录下&#xff1a; {"diffEditor.ignoreTrimWhitespace": false,"files.autoSave": "afterDelay","editor.codeActionsOnSave": {"source.fixAll.eslint"…

【leetcode】消失的数字

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家刷题&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 1.暴力求解法2.采用异或的方法&#xff08;同单身狗问题&#xff09;3.先求和再减去数组元素 点击查看…

Leetcode刷题笔记题解(C++):200. 岛屿数量

思路&#xff1a;利用深度优先搜索的思路来查找1身边的1&#xff0c;并且遍历之后进行0替换防止重复dfs&#xff0c;代码如下所示 class Solution { public:int numIslands(vector<vector<char>>& grid) {int row grid.size();int col grid[0].size();int n…

Unity之四元数

欧拉角 万向节死锁 四元数是什么 Unity中四元数的初始化 四元数和欧拉角的互相转换 补充 四元数相乘代表旋转四元数

一张图描述Http常用状态码(301、302、305、404、408等等)

301—永久移动。被请求的资源已被永久移动位置&#xff1b; 302—请求的资源现在临时从不同的 URI 响应请求&#xff1b; 305—使用代理。被请求的资源必须通过指定的代理才能被访问&#xff1b; 307—临时跳转。被请求的资源在临时从不同的URL响应请求&#xff1b; 40…

往docker中cloudbeaver的容器添加达梦数据库、impala数据库连接支持(cloudbeaver添加自定义数据连接)

cloudbeaver默认没有开放impala连接&#xff0c;更不会支持国产数据库了 docker安装运行cloudbeaver可以参考文章&#xff1a;docker安装运行CloudBeaver并设置默认语言为中文 本文跳过cloudbeaver镜像拉取&#xff0c;直接就开始实现自定义数据库连接功能 1、初始化cloudbe…

浅谈:完成一篇论文的科研历程与经验

作者&#xff1a;彭思达 | CCF专业会员 浙江大学研究员 主要研究方向为三维计算机视觉 | 本文版权归作者所有 文章目录 引言阶段1&#xff1a;想idea阶段2&#xff1a;如何做实验阶段3&#xff1a;如何写论文 引言 完成一篇论文的常见科研历程包括三大阶段&#xff1a;想idea、…