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 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://www.mfbz.cn/a/332867.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

k8s之对外服务ingress

一、service 1、service作用 ①集群内部&#xff1a;不断跟踪pod的变化&#xff0c;不断更新endpoint中的pod对象&#xff0c;基于pod的IP地址不断变化的一种服务发现机制&#xff08;endpoint存储最终对外提供服务的IP地址和端口&#xff09; ②集群外部&#xff1a;类似负…

canal调度控制器CanalController源码分析

canal调度控制器初始化&#xff1a; public CanalController(final Properties properties) 1. 初始化instance公共全局配置&#xff1a; canal.instance.global.(mode、lazy、manager.address以及spring.xml&#xff0c;并放入内存 InstanceConfig globalInstanceConfig; …

看完买,开放式耳机质量榜单:南卡夺冠、韶音第5、Cleer排第7

​作为一名拥有丰富经验的开放式耳机用户&#xff0c;我想在此提醒大家&#xff0c;选择耳机时&#xff0c;千万不要盲目跟风或过于信赖所谓的“网红”或“大牌产品”。毕竟&#xff0c;每个人的需求和使用环境都是独一无二的&#xff0c;因此&#xff0c;适合自己的耳机才是最…

AP5191DC-DC宽电压LED降压恒流驱动器

产品描述 AP5191是一款PWM工作模式,高效率、外围 简 单、外置功率MOS管&#xff0c;适用于4.5-150V输入的高 精度降压LED恒流驱动芯片。输出最大功率150W&#xff0c; 最大电流6A。 AP5191可实现线性调光和PWM调光&#xff0c;线性 调 光脚有效电压范围0.55-2.6V. AP519…

centos7 arm服务器编译安装PaddlePaddle

前言 随着国产服务器发展&#xff0c;部署项目需要用在国产服务器上&#xff0c;官方教程里面很多没有讲解到&#xff0c;安装过程中出现了各种各样的问题&#xff0c;以下是对官方教程的补充&#xff0c;有什么问题&#xff0c;欢迎指正&#xff01; 一、环境准备 gcc: 8.2版…

(工具变量)各地区-距沿海港口最短距离汇总数据集

全国各省距沿海港口最短距离数据提供了中国各省份与最近海港之间的最短地理距离信息。这些数据对于理解和分析中国各省的地理优势、物流效率以及对外贸易潜力有一定帮助。沿海港口作为国际贸易的重要节点&#xff0c;其距离对于省份的出口入口物流成本、运输时间以及总体贸易便…

vue $attrs和$listenners

Vue2.x 中的a t t r s 和 attrs和attrs和listeners 或许很多Vue小白跟我一样, 在之前不太了解a t t r s 和 attrs和attrs和listenners这两个API是干嘛的, 甚至没有听过或者使用过。下面我来浅述一下我对这两个API的理解。 下文将基于下面这张图片来进行解释&#xff0c;现在我…

《Python数据分析技术栈》第01章 02 Jupyter入门(Getting started with Jupyter notebooks)

02 Jupyter入门&#xff08;Getting started with Jupyter notebooks&#xff09; 《Python数据分析技术栈》第01章 02 Jupyter入门&#xff08;Getting started with Jupyter notebooks&#xff09; Before we discuss the essentials of Jupyter notebooks, let us discuss…

VSCode使用Makefile Tools插件开发C/C++程序

提起Makefile&#xff0c;可能有人会觉得它已经过时了&#xff0c;毕竟现在有比它更好的工具&#xff0c;比如CMake&#xff0c;XMake&#xff0c;Meson等等&#xff0c;但是在Linux下很多C/C源码都是直接或者间接使用Makefile文件来编译项目的&#xff0c;可以说Makefile是基石…

RT Thread Stdio生成STM32L431RCT6工程后如何修改外部时钟

一、简介 RT Thread Stdio生成STM32L431RCT6工程后默认为内部时钟&#xff0c;如何修改为外部时钟呢&#xff1f; 二、修改时钟步骤 本方案修改外部时钟为直接修改代码&#xff0c;不通过STM32CubeMX 进行配置&#xff08;使用这个软件会编译出错&#xff09; &#xff08;…

AEB滤镜再破碎,安全焦虑「解不开」?

不久前&#xff0c;理想L7重大交通事故&#xff0c;再次引发了公众对AEB的热议。 根据理想汽车公布的事故视频显示&#xff0c;碰撞发生前3秒&#xff0c;车速在178km/h时驾驶员采取了制动措施&#xff0c;但车速大幅超出AEB&#xff08;自动紧急刹车系统&#xff09;的工作范…

为什么 Golang Fasthttp 选择使用 slice 而非 map 存储请求数据

文章目录 Slice vs Map&#xff1a;基本概念内存分配和性能Fasthttp 中的 SliceMap性能优化的深层原因HTTP Headers 的特性CPU 预加载特性 结论 Fasthttp 是一个高性能的 Golang HTTP 框架&#xff0c;它在设计上做了许多优化以提高性能。其中一个显著的设计选择是使用 slice 而…

用sdkman在linux上管理多个java版本

概述&#xff1a; SDKMAN 是一个用于管理软件开发工具的工具&#xff0c;允许您轻松地安装、升级和切换不同版本的 JDK、Maven、Gradle 等工具。以下是在 Linux 上安装 SDKMAN! 的基本步骤&#xff1a; 安装SdkMan 使用 curl 安装 SDKMAN!: 打开终端&#xff0c;并运行以下命…

SpringCloud之Nacos

一、微服务介绍 1. 什么是微服务 2014年,Martin Fowler(马丁福勒 ) 提出了微服务的概念,定义了微服务是由以单一应用程序构成的小服务,自己拥有自己的进程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用 HTTP API 通信。同时服务会使用最小的规模…

eNSP学习——配置通过Telnet登陆系统

实验内容&#xff1a; 模拟公司网络场景。R1是机房的设备&#xff0c;办公区与机房不在同一楼层&#xff0c;R2和R3模拟员工主机&#xff0c; 通过交换机S1与R1相连。 为了方便用户的管理&#xff0c;需要在R1上配置Telnet使员工可以在办公区远程管理机房设备。 为…

德施曼智能锁×去哪儿跨界联名,送你一场说走就走的新年旅行~

2024年农历新年即将来临&#xff0c;智能锁行业领军企业德施曼携手中国领先在线旅游平台去哪儿&#xff0c;紧扣“旅游过年”的新年趋势&#xff0c;推出“新年去哪儿&#xff0c;德施曼替你看家”跨界联名活动&#xff0c;为广大用户带来一场说走就走的旅行。 德施曼X去哪儿 …

学习笔记之——3D Gaussian SLAM,SplaTAM配置(Linux)与源码解读

SplaTAM全称是《SplaTAM: Splat, Track & Map 3D Gaussians for Dense RGB-D SLAM》&#xff0c;是第一个&#xff08;也是目前唯一一个&#xff09;开源的用3D Gaussian Splatting&#xff08;3DGS&#xff09;来做SLAM的工作。 在下面博客中&#xff0c;已经对3DGS进行了…

让CHAT对springSecurity原理进行简述

CHAT回复&#xff1a;Spring Security是Spring框架中用于实现认证和授权功能的安全框架。其主要原理基于Filter机制&#xff0c;可以实现基于角色或者资源URL的访问控制。 具体来说&#xff0c;Spring Security通过一系列的Filter对Web请求进行拦截&#xff0c;然后根据用户提供…

短视频代运营抖音项目规划管理计划模板

【干货资料持续更新&#xff0c;以防走丢】 短视频代运营抖音项目规划管理计划模板 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 短视频代运营模板&#xff08;完整资料包含以下内容&#xff09; 目录 具体的表格设计和内容可能因不同的情况和需求而有所变…

基于YOLOv8深度学习的葡萄簇目标检测系统【python源码+Pyqt5界面+数据集+训练代码】目标检测、深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…
最新文章