C++ 类与对象Oop

news/2024/7/7 21:53:06

类与对象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 member

public:
    void setData(int value); // Member function declaration
    int 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 和 getter
    void 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坐标为3
    p.setY(4); // 设置Y坐标为4
    cout << "Point坐标: (" << p.getX() << ", " << p.getY() << ")" << endl;

    // 创建Circle对象
    Circle c;
    c.setC_R(5); // 设置圆的半径为5
    c.setC_Center(p); // 设置圆心坐标为Point对象p
    cout << "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_H

class 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://lihuaxi.xjx100.cn/news/1973569.html

相关文章

一文读懂:工业用信号隔离器

信号隔离器是一种用于隔离电路信号的电子设备。它的作用在于将一个电路中的信号隔离开来&#xff0c;防止干扰和电磁干扰的影响。在现代工业和通信领域&#xff0c;信号隔离器已经成为了一种重要的工具&#xff0c;被广泛应用于各种不同的场合。 1.信号隔离器可用于保护电路。…

python贪吃蛇游戏

为了实现这个游戏&#xff0c;需要用到Python的pygame模块&#xff0c;它是一个专门用于开发游戏的模块&#xff0c;提供了很多方便的功能&#xff0c;比如窗口、图形、音效、事件处理等。 用pygame来创建一个窗口&#xff0c;设置游戏的背景色&#xff0c;画出蛇和食物&#…

什么是开放寻址法

开放寻址法&#xff08;Open Addressing&#xff09;是一种解决哈希冲突的方法&#xff0c;其中如果一个哈希表位置被占用了&#xff0c;就去寻找下一个可用的位置&#xff0c;直到找到一个空槽或者遍历整个表。这种方法避免了使用额外的数据结构&#xff08;比如链表&#xff…

ONLYOFFICE:开源、免费、安全,打造定制化办公平台的最佳选择

文章目录 写在前面ONLYOFFICE是什么&#xff1f;ONLYOFFICE的惊艳之处齐全的插件&#xff0c;助你锦上添花部署一款自己的安全可靠的办公平台写在最后 写在前面 说起 Office 办公软件&#xff0c;我想大家最常用的应该就是微软的 Microsoft Office 以及国产的 WPS Office。两款…

【音视频原理】图像相关概念 ② ( 帧率 | 常见帧率标准 | 码率 | 码率单位 )

文章目录 一、帧率1、帧率简介2、常见帧率标准3、帧率 刷新率 二、码率1、码率简介2、码率单位 一、帧率 1、帧率简介 帧率 Frame Rate , 帧 指的是 是 画面帧 , 帧率 是 画面帧 的 速率 ; 帧率 的 单位是 FPS , Frames Per Second , 是 每秒钟 的 画面帧 个数 ; 帧率 是 动画…

IP 网络分为接入网、城域网和骨干网

根据前述的IP 网络设计思想&#xff0c;结合算力网络对 正网络的需求分析&#xff0c;卫网络的具体实现可以从架构设计利网络技术两个方面进行总体设计。 首先从架构设计上考虑&#xff0c;架构应尽量简化&#xff0c;做到“以简应繁”。因此&#xff0c;整体网络架构不宜设计…

【协议】HTTP、HTTPS和HTTP2.0学习总结

1. TCP/IP四层协议 记得大学学网络课程的时候&#xff0c;学的都是OSI/RM七层协议&#xff0c;应用层 -> 表示层 -> 会话层 -> 传输层->网络层->数据链路层->物理层&#xff0c;当时学的时候&#xff0c;感觉太抽象了&#xff0c;学得个一知半解。大脑在接收…

multipass方便创建虚拟机

安装 https://multipass.run/ windows安装之后可能powershell或者cmd打不开的情况。 可以在安装目录下按住shift点击鼠标右键的方式打开powershell&#xff0c;在这个powershell中进行操作。 显示虚拟机信息 <实例名称> multipass info 修改驱动 multipass set loca…