1.类的引入
类的引入是面向对象编程(OOP)中的一个基本概念,它代表了面向对象编程范式的核心。在C++中,类(Class)是一种用户定义的数据类型,它将数据表示(属性)和操作数据的方法(函数)组合成一个单一的实体。
class ClassName { // 类的成员变量(属性) // 类的成员函数(方法)public: // 公有成员(可以被类外部访问)protected: // 保护成员(可以被类自身、派生类以及友元函数访问)private: // 私有成员(只能被类自身访问)};
类的引入目的
模块化:类允许程序员将复杂的系统分解成更小、更易于管理的模块。代码复用:通过继承机制,类可以继承其他类的特性,减少代码重复。易于维护:由于类封装了数据和操作,因此更改类的内部实现不会影响到其他部分的代码。增强安全性:通过访问控制,类可以保护其数据不被不恰当的访问和修改。
2.类的定义
类定义的组成部分
访问修饰符:
public
:公有成员可以被类的外部访问。protected
:保护成员可以被类自身、派生类以及友元函数访问。private
:私有成员只能被类自身访问。 成员变量:类中定义的数据。
成员函数:类中定义的操作数据的函数。
构造函数:用于初始化类的对象。
析构函数:用于在对象生命周期结束时执行清理工作。
类定义的示例
#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++中,类定义了一个新的作用域,这意味着在类内部声明的名称(如成员变量和成员函数)在类的外部是不可见的,除非通过类的成员访问运算符(.
)或者指针/引用的箭头运算符(->
)来访问。以下是关于类作用域的一些关键点:
类作用域的特点:
成员变量和成员函数:
在类内部声明的成员变量和成员函数属于类的作用域。成员变量和成员函数默认是私有的,除非明确指定为public
或protected
。 名称隐藏:
类内部的名称会隐藏外部的同名名称。如果在类内部声明了一个与外部同名的变量或函数,那么在类的作用域内,这个内部名称会覆盖外部名称。作用域解析运算符:
如果需要在类外部访问类的成员,需要使用作用域解析运算符::
。 构造函数和析构函数:
构造函数和析构函数也属于类的作用域,它们在创建和销毁类的对象时被调用。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)字节。以下是计算类对象大小的几个关键点:
成员变量:类对象的大小至少是其所有非静态成员变量大小的总和。
成员对齐:每个成员变量可能有其特定的对齐要求。对象的内存布局会按照这些对齐要求来调整。
类对齐:整个类对象可能也有一个对齐要求,这会影响对象的总大小。
填充字节:编译器可能会在成员变量之间插入填充字节以满足对齐要求。
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
指针的一些关键点:
隐含参数:this
指针是隐含传递给成员函数的第一个参数。
类型:this
指针的类型是类类型的指针,例如MyClass*
。
用途:this
指针用于访问调用该函数的对象的成员变量和成员函数。
非静态成员函数:只有非静态成员函数才有this
指针。
默认值:在成员函数内部,可以显式地使用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指针