【C++】类与对象(一)

【C++】类与对象(一)_第1张图片

前言
类与对象(一)


文章目录

  • 一、面向对象和面向过程的对比
  • 二、类的引入
    • 2.1 C++中的结构体
    • 2.2 类
    • 2.3 类定义方法
    • 2.4 修饰限定符
    • 2.5 封装
    • 2.6 类的实例化
    • 2.7 类对象的大小
  • 三、this指针
    • 3.1 this 指针的使用

一、面向对象和面向过程的对比

面向过程编程是将程序看作一系列的步骤或过程,然后逐步完成各个步骤,从而实现一个程序的方法。而面向对象编程是将问题分解为对象,每个对象包含数据(属性)和操作数据的方法(方法)。

以将大象装进冰箱为例:
【C++】类与对象(一)_第2张图片
面向对象编程(OOP):

  • 大象对象: 有属性(大小、重量)和方法(进入冰箱)。
  • 冰箱对象: 有属性(容量、门的状态)和方法(打开门)。

面向过程编程:

  • 过程: 分解为步骤。打开冰箱的门,把大象放进去,关闭门。

我们知道面向过程的编程语言有C语言,现在我们来认识一下面向对象编程的编程语言的代表之一——C++。


二、类的引入

2.1 C++中的结构体

在C语言中我们可以使用struct(结构体)来自定义类型,同样在C++也有结构体的使用,但有所不同:

C++中的struct的特点:

  1. 默认访问修饰符: 在C++中,struct的成员默认是公有的(public,访问限定修饰符),与C语言中相同。

  2. 支持成员函数: 与C不同,C++中的struct可以包含成员函数。

    // 在C++中的struct示例
    struct Person {
        // 成员变量
        char name[50];
        int age;
    
        // 成员函数
        void displayInfo() {
            cout << "Name: " << name << "\nAge: " << age << endl;
        }
    };
    
  3. 继承和访问控制: C++中的struct也可以继承其他结构体或类,并且支持访问控制,包括私有、保护和公有继承。

    // 基类
    class Animal {
    public:
        void eat() {
            cout << "动物在吃东西。" << endl;
        }
    };
    
    // 派生类
    struct Dog : public Animal { // 公有继承
        void bark() {
            cout << "狗在叫" << endl;
        }
    };
    

C++中,struct可以更多地用于实现类似于类的结构。


2.2 类

初始版本的 C++ 在设计时候的一个目标是与 C 语言保持高度的兼容性,以便现有的 C 代码可以逐渐迁移到 C++ 中。因此保留了struct,并稍微扩展了其功能,可以包含函数,增加修饰限定符等。但struct的访问权限是默认是公有的,因此,C++中引入了类的概念。

C++中,类是一种用户自定义的数据类型,在语法上与struct非常相像。

类的基本结构包括成员变量(类的属性)成员函数(类的方法):

//class为关键字   Time为类名
class Time {
public:
    int hours;    //小时
    int minutes;  //分
    int seconds;  //秒
private:
    // 设置时间
    void setTime(int h, int m, int s);

    // 显示时间
    void displayTime();
};

2.3 类定义方法

有两种主要的类定义方式:定义在类外部的方式定义在类内部的方式

1. 定义在类外部的方式:

类的声明通常放在头文件(.h 文件)中,而类的定义则放在源文件(.cpp 文件)中。注意:成员函数定义时名字前需要加类名::,例如 int MyClass::getVar() const

示例:

// MyClass.h
#pragma once

class MyClass {
private:
    int myVar;

public:
    MyClass();  // 声明构造函数
    void setVar(int value);  // 声明成员函数
    int getVar() const;  // 声明成员函数
};

// MyClass.cpp
#include "MyClass.h"

MyClass::MyClass() {
    myVar = 0;
}

void MyClass::setVar(int value) {
    myVar = value;
}

int MyClass::getVar() const {
    return myVar;
}

2. 定义在类内部的方式:

类的声明和定义都放在类的内部。

示例:

// MyClass.h
#pragma once

class MyClass {
private:
    int myVar;

public:
    MyClass() {
        myVar = 0;
    }

    void setVar(int value) {
        myVar = value;
    }

    int getVar() const {
        return myVar;
    }
};

2.4 修饰限定符

在C++中,修饰限定符用于控制类中成员的访问权限。C++有三个主要的修饰限定符:publicprotectedprivate

  1. public: 成员被声明为公有,可以在类的外部和内部访问。
  2. protected: 成员被声明为受保护的,可以在类的内部和派生类中访问,但在类的外部不能直接访问。
  3. private: 成员被声明为私有,只能在类的内部访问,不能在类的外部或派生类中直接访问。

修饰限定符通常出现在类的定义中,用于指定类成员的访问权限。以下是一个简单的示例:

class MyClass {
public:
    // 公有成员
    int publicVar;

    // 公有成员函数
    void publicFunction() {
        // 可以访问公有、受保护、私有成员
        publicVar = 1;
        protectedVar = 2;
        privateVar = 3;
    }

protected:
    // 受保护成员
    int protectedVar;

private:
    // 私有成员
    int privateVar;
};

在上面的示例中,publicVar 是公有成员,可以在类的外部直接访问。protectedVar 是受保护成员,只能在类的内部和派生类中访问。privateVar 是私有成员,只能在类的内部访问。

需要注意的是:class的默认访问权限为private,struct为public(因为struct要兼容C,这也是为什么要引入类的原因)


2.5 封装

封装是面向对象编程(OOP)的一个核心概念,它指的是将数据和操作数据的方法封装在一个单一的实体(类)中,并对外部隐藏对象的内部实现细节。封装通过将数据成员私有化,并提供公有的成员函数来实现,使得外部代码无法直接访问对象的内部数据,而是通过类的接口进行交互。

封装的主要目的有以下几点:

  1. 隐藏实现细节: 封装允许将实现细节隐藏在类的内部,使得外部代码无法直接了解或修改类的内部数据结构和实现。

  2. 简化接口: 封装通过提供公有的接口(成员函数)来与对象进行交互,使得外部代码只需关心如何使用对象,而不需关心对象的内部工作方式。

  3. 提高代码的模块性: 封装将对象的实现细节封装在一个单一的单元中,使得代码模块化,易于维护和重用。

简单点说,封装就像是你有一辆车,但你不需要知道引擎是怎么工作的,也不需要了解车轮是如何旋转的。你只需要知道一些关于这辆车的基本信息,比如怎么加速、怎么刹车,这就是车的接口。引擎和其他细节都被封装在车的内部,对你来说是不可见的。


2.6 类的实例化

类就像建筑设计图,对象是按照设计图实际要建造的房子。而实例化就像是在建造房子的过程。
举例:

#include 
using namespace std;

// 定义一个简单的类
class Car {
public:
    // 成员变量
    string brand;
    int year;

    // 构造函数
    Car(string b, int y) : brand(b), year(y) {}

    // 成员函数
    void displayInfo() {
        cout << "Brand: " << brand << ", Year: " << year << endl;
    }
};

int main() {
    // 声明并实例化 Car 类的对象
    Car myCar("Toyota", 2022);

    // 使用对象的成员函数
    myCar.displayInfo();

    return 0;
}

2.7 类对象的大小

类的大小由其成员变量的大小总和决定,不包括成员函数的大小。成员函数在每个对象中共享相同的代码,因此它们不会增加对象的大小。

成员变量的大小由它们的类型和数量决定。每个基本数据类型(如int、double等)在内存中占用的空间是确定的,而类类型的大小取决于其成员变量的大小。

考虑一个简单的示例:

class MyClass {
public:
    int integerVar;
    double doubleVar;
    char charVar;
    
	void func1();
	void func2();
};

int main() {
    MyClass c1;
    cout << "c1的大小为" << sizeof(c1) << endl;
    return 0;
}

【C++】类与对象(一)_第3张图片
那么MyClass 类的对象大小将是24字节,当然这是在默认对齐数为8时的大小。

对象的大小也受到内存对齐的影响,可以参考这篇博文【C语言】自定义类型:结构体。


三、this指针

this 指针是一个特殊的指针,它指向当前对象的地址。

this 指针并不是一个明确存在于内存中的变量,而是编译器在代码生成阶段处理的一种机制,用于传递当前对象的地址给成员函数。

this 指针的存在是因为成员函数需要知道它们是在哪个对象上调用的,以便正确地访问该对象的成员变量和成员函数。

当你在类的成员函数中使用成员变量或调用成员函数时,编译器会隐式地将 this 指针传递给该函数,使得函数内部可以通过 this 指针来引用当前对象。

3.1 this 指针的使用

在类的成员函数中,可以使用 this 指针来引用当前对象的成员变量和成员函数。它允许在成员函数中访问当前对象的成员,即使成员的名称与参数名称相同也能够正确引用

在传参及接收参数时不能显式地标出this。

class MyClass {
private:
    int _x;

public:
    void setX(int x) {
        this->_x = x;  // 使用this指针引用成员变量
        
        //在 C++ 中,如果成员函数中使用的变量名与成员变量名相同,编译器会默认使用成员变量,这是一种默认约定
        // _x = x;    //或者直接使用成员变量名_x
        
    }

    int getX() const {
        return this->_x;  // 使用this指针引用成员变量
		
		//return _x;
    }
};

int main() {
    MyClass obj;
    obj.setX(42);   // 必须隐式地传递this指针给setX函数,即在实参不标出this,也不在形参标出
    int value = obj.getX();  // 隐式地传递this指针给getX函数
    cout << "value=" << value << endl;
}

【C++】类与对象(一)_第4张图片


【C++】类与对象(一)_第5张图片
如果你喜欢这篇文章,点赞+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。

你可能感兴趣的:(c++,开发语言)