当前位置: 首页 > article >正文

c++的类和对象(1)

1.类的引入

类的引入是面向对象编程(OOP)中的一个基本概念,它代表了面向对象编程范式的核心。在C++中,类(Class)是一种用户定义的数据类型,它将数据表示(属性)和操作数据的方法(函数)组合成一个单一的实体。 

class ClassName {
    // 类的成员变量(属性)
    // 类的成员函数(方法)
public:
    // 公有成员(可以被类外部访问)
protected:
    // 保护成员(可以被类自身、派生类以及友元函数访问)
private:
    // 私有成员(只能被类自身访问)
};

 

类的引入目的

  • 模块化:类允许程序员将复杂的系统分解成更小、更易于管理的模块。
  • 代码复用:通过继承机制,类可以继承其他类的特性,减少代码重复。
  • 易于维护:由于类封装了数据和操作,因此更改类的内部实现不会影响到其他部分的代码。
  • 增强安全性:通过访问控制,类可以保护其数据不被不恰当的访问和修改。


2.类的定义

类定义的组成部分

  1. 访问修饰符

    • public:公有成员可以被类的外部访问。
    • protected:保护成员可以被类自身、派生类以及友元函数访问。
    • private:私有成员只能被类自身访问。
  2. 成员变量:类中定义的数据。

  3. 成员函数:类中定义的操作数据的函数。

  4. 构造函数:用于初始化类的对象。

  5. 析构函数:用于在对象生命周期结束时执行清理工作。

类定义的示例

#include <string>

class Person {
private:
    // 私有成员变量
    std::string name;
    int age;

public:
    // 构造函数
    Person(std::string n, int a) : name(n), age(a) {}

    // 成员函数,设置姓名
    void setName(std::string n) {
        name = n;
    }

    // 成员函数,获取姓名
    std::string getName() const {
        return name;
    }

    // 成员函数,设置年龄
    void setAge(int a) {
        age = a;
    }

    // 成员函数,获取年龄
    int getAge() const {
        return age;
    }

    // 成员函数,显示个人信息
    void display() const {
        std::cout << "Name: " << name << ", Age: " << age << std::endl;
    }
};


3.类的封装

封装

封装是一种将数据和操作数据的函数捆绑在一起的方法,以防止外部直接访问类的内部工作细节。封装的目的包括:

  • 隐藏实现细节:用户不需要知道类的内部工作方式,只需要知道如何使用它。
  • 保护数据:防止外部直接修改类的内部状态,确保数据的一致性和完整性。
  • 模块化:通过封装,类的内部实现可以独立于其他类的实现进行更改,而不会影响使用该类的代码。
class BankAccount {
private:
    // 私有成员变量,只能被类内部访问
    double balance;

public:
    // 构造函数,初始化账户余额
    BankAccount(double initialBalance) : balance(initialBalance) {}

    // 公有成员函数,用于存钱
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }

    // 公有成员函数,用于取钱
    bool withdraw(double amount) {
        if (amount > 0 && balance >= amount) {
            balance -= amount;
            return true;
        } else {
            return false;
        }
    }

    // 公有成员函数,获取账户余额
    double getBalance() const {
        return balance;
    }
};

int main() {
    BankAccount account(1000.0); // 创建账户,初始余额为1000

    account.deposit(500.0); // 存入500
    account.withdraw(200.0); // 取出200

    // 尝试直接访问私有成员变量(错误,编译器将报错)
    // account.balance = 0; 

    std::cout << "Current balance: " << account.getBalance() << std::endl; // 正确地获取余额

    return 0;
}

4.类的作用域

在C++中,类定义了一个新的作用域,这意味着在类内部声明的名称(如成员变量和成员函数)在类的外部是不可见的,除非通过类的成员访问运算符(.)或者指针/引用的箭头运算符(->)来访问。以下是关于类作用域的一些关键点:

类作用域的特点:

  1. 成员变量和成员函数

    • 在类内部声明的成员变量和成员函数属于类的作用域。
    • 成员变量和成员函数默认是私有的,除非明确指定为publicprotected
  2. 名称隐藏

    • 类内部的名称会隐藏外部的同名名称。如果在类内部声明了一个与外部同名的变量或函数,那么在类的作用域内,这个内部名称会覆盖外部名称。
  3. 作用域解析运算符

    • 如果需要在类外部访问类的成员,需要使用作用域解析运算符::
  4. 构造函数和析构函数

    • 构造函数和析构函数也属于类的作用域,它们在创建和销毁类的对象时被调用。
class MyClass {
public:
    int publicVar; // 公有成员变量
    void publicFunc() { // 公有成员函数
        // 在这里可以访问类的所有成员
    }

private:
    int privateVar; // 私有成员变量
    void privateFunc() { // 私有成员函数
        // 在这里可以访问类的所有成员
    }

    // 构造函数
    MyClass() {
        privateVar = 0;
    }
};

int main() {
    MyClass obj;

    // 访问公有成员
    obj.publicVar = 10; // 正确
    obj.publicFunc();   // 正确

    // 尝试访问私有成员(错误,编译器将报错)
    // obj.privateVar = 20; // 错误
    // obj.privateFunc();   // 错误

    return 0;
}

 

类的对象大小的计算

在C++中,类对象的大小取决于其成员变量的大小、对齐要求以及可能的填充(padding)字节。以下是计算类对象大小的几个关键点:

  1. 成员变量:类对象的大小至少是其所有非静态成员变量大小的总和。

  2. 成员对齐:每个成员变量可能有其特定的对齐要求。对象的内存布局会按照这些对齐要求来调整。

  3. 类对齐:整个类对象可能也有一个对齐要求,这会影响对象的总大小。

  4. 填充字节:编译器可能会在成员变量之间插入填充字节以满足对齐要求。

 

class MyClass {
    int a;       // 通常占用4字节
    char b;      // 占用1字节
    double c;    // 通常占用8字节
    // 可能的填充字节
};
// 假设默认对齐数为8
// 计算过程:
// a占用4字节,b占用1字节,但由于double需要对齐到8字节,所以b之后会有3字节的填充
// c占用8字节
// 因此,MyClass对象的总大小为:4 + 1 + 3(填充) + 8 = 16字节

类成员函数的this指针

在C++中,每个非静态成员函数都有一个隐含的参数,称为this指针。this指针指向调用该成员函数的对象本身。以下是关于this指针的一些关键点:

  1. 隐含参数this指针是隐含传递给成员函数的第一个参数。

  2. 类型this指针的类型是类类型的指针,例如MyClass*

  3. 用途this指针用于访问调用该函数的对象的成员变量和成员函数。

  4. 非静态成员函数:只有非静态成员函数才有this指针。

  5. 默认值:在成员函数内部,可以显式地使用this指针,也可以省略它,因为编译器会自动添加。

class MyClass {
public:
    int value;

    void setValue(int val) {
        this->value = val; // 使用this指针显式地设置成员变量
    }

    int getValue() const {
        return this->value; // 使用this指针显式地获取成员变量
    }
};

MyClass obj;
obj.setValue(10); // 调用时,编译器会隐含传递this指针
int val = obj.getValue(); // 同样,编译器会隐含传递this指针


http://www.kler.cn/a/408685.html

相关文章:

  • c++ unordered_set和unordered_map
  • 图论最短路(floyed+ford)
  • 一文学习Android系统核心服务ServiceManager
  • apache、iis屏蔽限制ip访问(适用虚拟主机)
  • 3D建筑模型的 LOD 规范
  • 07-Making a Bar Chart with D3.js and SVG
  • PDF内容提取,MinerU使用
  • vscode + ROS 配置快捷编译
  • 【C++】从C语言到C++学习指南
  • GESP语法知识(快速排序)
  • VRRP虚拟路由实现主备设备负载分担
  • 在Spring Boot项目中集成RabbitMQ消息中间件
  • JSON 性能测试 - WastJson 性能也很快
  • 基于LiteFlow的风控系统指标版本控制
  • ApiChain 从迭代测试用例到项目回归测试 核心使用教程
  • 知乎日报——第二周
  • 乐鑫ESP32物联网方案,设备人机交互技术应用,启明云端乐鑫代理商
  • Java连接MySQL数据库进行增删改查操作
  • Flink-Source的使用
  • (二)手势识别——动作模型训练【代码+数据集+python环境(免安装)+GUI系统】
  • -Dspring.profiles.active=dev与--spring.profiles.active=dev的区别
  • 默语博主的推荐:探索技术世界的旅程
  • 8、深入剖析PyTorch的state_dict、parameters、modules源码
  • GCC编译过程(预处理,编译,汇编,链接)及GCC命令
  • 如果在docker 容器中安装ros遇到的问题
  • 《MySQL 事务隔离级别详解》