====== 第五章 类与对象 ======
本章将详细介绍C++的面向对象编程基础——类与对象,包括类的定义、构造函数、析构函数、this指针等核心概念。
===== 5.1 类的基本概念 =====
=== 5.1.1 类的定义 ===
类是C++中实现面向对象编程的基础,是用户自定义的数据类型,包含数据成员和成员函数。
#include
#include
using namespace std;
// 类的定义
class Student {
// 访问控制修饰符
public: // 公有成员,外部可访问
// 成员函数(方法)
void setName(string n) {
name = n;
}
string getName() const {
return name;
}
void setAge(int a) {
if (a > 0 && a < 150) {
age = a;
}
}
int getAge() const {
return age;
}
void displayInfo() const {
cout << "Name: " << name << ", Age: " << age << endl;
}
private: // 私有成员,只能在类内部访问
// 数据成员
string name;
int age;
};
int main() {
// 创建对象
Student stu1;
// 使用成员函数
stu1.setName("Alice");
stu1.setAge(20);
stu1.displayInfo();
// 错误:无法直接访问私有成员
// stu1.name = "Bob";
// stu1.age = 25;
return 0;
}
=== 5.1.2 访问控制 ===
| 访问修饰符 | 类内部 | 派生类 | 外部 |
|-----------|--------|--------|------|
| public | ✓ | ✓ | ✓ |
| protected | ✓ | ✓ | ✗ |
| private | ✓ | ✗ | ✗ |
#include
using namespace std;
class BankAccount {
public:
// 公有接口
void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
bool withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
}
double getBalance() const {
return balance;
}
protected:
// 受保护成员,派生类可访问
string accountType = "Standard";
private:
// 私有数据,封装实现细节
double balance = 0.0;
string password;
bool verifyPassword(const string& pwd) {
return password == pwd;
}
};
=== 5.1.3 struct与class的区别 ===
#include
using namespace std;
// struct:默认public
struct Point {
double x; // 默认public
double y;
void move(double dx, double dy) {
x += dx;
y += dy;
}
};
// class:默认private
class Point2 {
double x; // 默认private
double y;
public:
void set(double xVal, double yVal) {
x = xVal;
y = yVal;
}
void move(double dx, double dy) {
x += dx;
y += dy;
}
};
int main() {
Point p1;
p1.x = 10; // 可以直接访问
p1.y = 20;
Point2 p2;
// p2.x = 10; // 错误!x是private
p2.set(10, 20); // 必须通过公有接口
return 0;
}
===== 5.2 构造函数 =====
=== 5.2.1 默认构造函数 ===
#include
#include
using namespace std;
class Person {
public:
// 默认构造函数(无参数)
Person() {
name = "Unknown";
age = 0;
cout << "Default constructor called" << endl;
}
// 带参数的构造函数
Person(string n, int a) {
name = n;
age = a;
cout << "Parameterized constructor called" << endl;
}
void display() const {
cout << "Name: " << name << ", Age: " << age << endl;
}
private:
string name;
int age;
};
int main() {
Person p1; // 调用默认构造函数
Person p2("Alice", 20); // 调用带参数的构造函数
Person p3 = Person("Bob", 25); // 显式调用
Person p4{"Charlie", 30}; // 列表初始化(C++11)
p1.display();
p2.display();
p3.display();
p4.display();
return 0;
}
=== 5.2.2 构造函数初始化列表 ===
#include
using namespace std;
class Member {
public:
Member(int v) : value(v) {
cout << "Member constructed with " << value << endl;
}
private:
int value;
};
class Container {
public:
// 使用初始化列表
Container(int a, int b, int c)
: x(a), y(b), z(c), member(a) {
// 初始化列表中初始化成员
// 比构造函数体内赋值效率更高
}
// 错误的做法(不能用于const成员和引用成员)
// Container(int a, int b, int c) {
// x = a; // 这是赋值,不是初始化
// y = b;
// z = c;
// }
private:
int x, y, z;
Member member; // 没有默认构造函数的成员
const int CONST_VAL = 100; // const成员必须在初始化列表中初始化
int& ref; // 引用成员必须在初始化列表中初始化
};
int main() {
Container c(1, 2, 3);
return 0;
}
=== 5.2.3 委托构造函数(C++11) ===
#include
#include
using namespace std;
class Rectangle {
public:
// 主构造函数
Rectangle(double w, double h, string c)
: width(w), height(h), color(c) {
cout << "Main constructor" << endl;
}
// 委托构造函数
Rectangle() : Rectangle(1.0, 1.0, "white") {
cout << "Delegating constructor (default)" << endl;
}
Rectangle(double w, double h) : Rectangle(w, h, "white") {
cout << "Delegating constructor (no color)" << endl;
}
Rectangle(double side) : Rectangle(side, side, "white") {
cout << "Delegating constructor (square)" << endl;
}
void display() const {
cout << width << "x" << height << " " << color << endl;
}
private:
double width, height;
string color;
};
int main() {
Rectangle r1; // 默认
Rectangle r2(3, 4); // 无颜色
Rectangle r3(5); // 正方形
Rectangle r4(2, 3, "red"); // 全参数
r1.display();
r2.display();
r3.display();
r4.display();
return 0;
}
=== 5.2.4 拷贝构造函数 ===
#include
#include
using namespace std;
class String {
public:
// 普通构造函数
String(const char* str = "") {
size = strlen(str);
data = new char[size + 1];
strcpy(data, str);
cout << "Constructor: " << data << endl;
}
// 拷贝构造函数
String(const String& other) {
size = other.size;
data = new char[size + 1];
strcpy(data, other.data);
cout << "Copy constructor: " << data << endl;
}
// 析构函数
~String() {
cout << "Destructor: " << (data ? data : "null") << endl;
delete[] data;
}
void display() const {
cout << data << endl;
}
private:
char* data;
size_t size;
};
// 拷贝构造函数被调用的情况
String createString() {
String s("Hello");
return s; // 可能触发拷贝构造(取决于优化)
}
void takeStringByValue(String s) {
s.display();
}
int main() {
String s1("World"); // 普通构造
String s2 = s1; // 拷贝构造
String s3(s1); // 拷贝构造(显式)
takeStringByValue(s1); // 拷贝构造(传递参数)
// String s4 = createString(); // 可能触发拷贝构造
return 0;
}
===== 5.3 析构函数 =====
=== 5.3.1 析构函数基础 ===
#include
using namespace std;
class Resource {
public:
Resource() {
data = new int[100];
cout << "Resource acquired" << endl;
}
// 析构函数
~Resource() {
delete[] data;
cout << "Resource released" << endl;
}
void doWork() {
cout << "Working..." << endl;
}
private:
int* data;
};
void functionScope() {
Resource r; // 构造
r.doWork();
// r在这里超出作用域,自动调用析构函数
}
int main() {
cout << "Entering main" << endl;
functionScope();
cout << "Creating dynamic object" << endl;
Resource* ptr = new Resource();
ptr->doWork();
delete ptr; // 必须手动delete才能调用析构函数
cout << "Leaving main" << endl;
return 0;
}
=== 5.3.2 析构函数的调用时机 ===
#include
using namespace std;
class Demo {
public:
Demo(int id) : id(id) {
cout << "Constructor: " << id << endl;
}
~Demo() {
cout << "Destructor: " << id << endl;
}
private:
int id;
};
// 全局对象
Demo globalObj(1); // 最先构造,最后析构
int main() {
cout << "--- Enter main ---" << endl;
Demo localObj(2); // main中构造
{
cout << "--- Enter block ---" << endl;
Demo blockObj(3); // 块中构造
cout << "--- Leave block ---" << endl;
// blockObj在这里析构
}
static Demo staticObj(4); // 只构造一次,程序结束时析构
Demo* ptr = new Demo(5); // 动态对象
delete ptr; // 手动析构
cout << "--- Leave main ---" << endl;
// localObj在这里析构
return 0;
}
// staticObj在这里析构
// globalObj在这里析构(最后)
===== 5.4 this指针 =====
=== 5.4.1 this指针的基础 ===
#include
using namespace std;
class Counter {
public:
Counter(int count = 0) : count(count) {}
// this指针指向调用成员函数的对象
Counter& increment() {
this->count++; // 等价于 count++;
return *this; // 返回当前对象的引用
}
Counter& add(int value) {
count += value;
return *this;
}
// 解决命名冲突
void setValue(int count) {
this->count = count; // 成员变量 = 参数
}
int getCount() const {
return count;
}
private:
int count;
};
int main() {
Counter c(0);
// 链式调用
c.increment().increment().add(5);
cout << "Count: " << c.getCount() << endl; // 7
return 0;
}
=== 5.4.2 this指针的应用 ===
#include
using namespace std;
class Node {
public:
Node(int val) : value(val), next(nullptr) {}
// 返回this实现链式插入
Node* append(int val) {
Node* newNode = new Node(val);
Node* current = this;
while (current->next != nullptr) {
current = current->next;
}
current->next = newNode;
return this;
}
void display() const {
const Node* current = this;
while (current != nullptr) {
cout << current->value << " -> ";
current = current->next;
}
cout << "null" << endl;
}
// 比较对象
bool isSameObject(const Node& other) const {
return this == &other;
}
private:
int value;
Node* next;
};
int main() {
Node* head = new Node(1);
head->append(2)->append(3)->append(4);
head->display(); // 1 -> 2 -> 3 -> 4 -> null
Node n1(1), n2(1);
cout << "Same object? " << n1.isSameObject(n2) << endl; // 0
cout << "Same object? " << n1.isSameObject(n1) << endl; // 1
return 0;
}
===== 5.5 静态成员 =====
=== 5.5.1 静态数据成员 ===
#include
using namespace std;
class Student {
public:
Student(string n) : name(n) {
count++;
id = count;
cout << "Student " << name << " created, total: " << count << endl;
}
~Student() {
count--;
cout << "Student " << name << " destroyed, total: " << count << endl;
}
static int getCount() {
return count;
}
void display() const {
cout << "ID: " << id << ", Name: " << name << endl;
}
private:
string name;
int id;
static int count; // 静态成员声明
};
// 静态成员定义和初始化
int Student::count = 0;
int main() {
cout << "Initial count: " << Student::getCount() << endl;
Student s1("Alice");
Student s2("Bob");
cout << "Current count: " << Student::getCount() << endl;
{
Student s3("Charlie");
cout << "Count in block: " << Student::getCount() << endl;
}
cout << "Final count: " << Student::getCount() << endl;
return 0;
}
=== 5.5.2 静态成员函数 ===
#include
using namespace std;
class MathUtils {
public:
// 静态成员函数
static int max(int a, int b) {
return (a > b) ? a : b;
}
static int min(int a, int b) {
return (a < b) ? a : b;
}
static double circleArea(double radius) {
return PI * radius * radius;
}
// 静态成员函数不能访问非静态成员
// static void badFunc() {
// nonStaticVar = 10; // 错误!
// }
private:
static constexpr double PI = 3.14159;
int nonStaticVar = 0;
};
// constexpr静态成员可以在类内初始化
double MathUtils::PI; // 在类外定义(C++17前需要)
int main() {
// 通过类名调用静态成员函数
cout << "Max: " << MathUtils::max(10, 20) << endl;
cout << "Min: " << MathUtils::min(10, 20) << endl;
cout << "Area: " << MathUtils::circleArea(5.0) << endl;
// 也可以通过对象调用(不推荐)
MathUtils mu;
cout << "Max: " << mu.max(30, 40) << endl;
return 0;
}
===== 5.6 const成员函数 =====
#include
using namespace std;
class Date {
public:
Date(int y, int m, int d) : year(y), month(m), day(d) {}
// const成员函数:不修改对象状态
int getYear() const {
// year = 2024; // 错误!不能修改成员
return year;
}
int getMonth() const { return month; }
int getDay() const { return day; }
void setYear(int y) {
year = y; // 非const函数可以修改成员
}
// const成员函数可以调用其他const成员函数
void display() const {
cout << year << "-" << month << "-" << day << endl;
// setYear(2024); // 错误!不能调用非const函数
}
// mutable成员:即使在const函数中也能修改
void incrementAccessCount() const {
accessCount++; // 合法,因为accessCount是mutable
}
private:
int year, month, day;
mutable int accessCount = 0; // 可变成员
};
int main() {
Date d1(2024, 1, 15);
const Date d2(2024, 6, 1);
d1.setYear(2025); // 合法
// d2.setYear(2025); // 错误!const对象不能调用非const函数
d1.display(); // 合法
d2.display(); // 合法(display是const函数)
d2.incrementAccessCount(); // 合法(修改mutable成员)
return 0;
}
===== 5.7 友元 =====
=== 5.7.1 友元函数 ===
#include
using namespace std;
class Box {
public:
Box(double w, double h, double d)
: width(w), height(h), depth(d) {}
// 声明友元函数
friend double calculateVolume(const Box& box);
friend class BoxManager; // 友元类
// 声明另一个类的成员函数为友元
friend void externalFunction(const Box& box);
private:
double width, height, depth;
};
// 友元函数可以访问私有成员
double calculateVolume(const Box& box) {
return box.width * box.height * box.depth;
}
// 友元类
class BoxManager {
public:
void resize(Box& box, double factor) {
// 可以访问Box的私有成员
box.width *= factor;
box.height *= factor;
box.depth *= factor;
}
double getSurfaceArea(const Box& box) {
return 2 * (box.width * box.height +
box.height * box.depth +
box.width * box.depth);
}
};
int main() {
Box box(3, 4, 5);
cout << "Volume: " << calculateVolume(box) << endl;
BoxManager manager;
cout << "Surface Area: " << manager.getSurfaceArea(box) << endl;
manager.resize(box, 2);
cout << "New Volume: " << calculateVolume(box) << endl;
return 0;
}
===== 5.8 本章小结 =====
本章我们学习了:
* 类的定义和访问控制(public、protected、private)
* 构造函数:默认构造、带参数构造、初始化列表、委托构造
* 拷贝构造函数和深拷贝
* 析构函数及其调用时机
* this指针的使用
* 静态成员变量和静态成员函数
* const成员函数和mutable
* 友元函数和友元类
===== 练习题 =====
**基础练习:**
1. 设计一个Book类,包含书名、作者、价格,提供相应的getter和setter
2. 实现一个计数器类,使用静态成员统计创建的对象数量
3. 编写一个字符串类MyString,实现构造函数和析构函数,管理动态内存
4. 实现一个BankAccount类,支持存款、取款、查询余额,确保余额不为负
**进阶练习:**
5. 设计一个矩阵类Matrix,支持基本的矩阵运算
6. 实现一个单向链表类LinkedList,包含插入、删除、查找操作
7. 创建一个日期类Date,支持日期计算(加减天数)
**思考题:**
8. 什么时候应该使用explicit关键字?举例说明
9. 分析以下代码的问题:
String func() {
String s("Hello");
return s;
}
int main() {
String s2 = func();
}
10. 比较深拷贝和浅拷贝,什么时候需要自定义拷贝构造函数?
===== 参考答案 =====
**练习2参考:**
class Counter {
private:
static int count;
int id;
public:
Counter() {
count++;
id = count;
}
~Counter() { count--; }
static int getCount() { return count; }
int getId() const { return id; }
};
int Counter::count = 0;
**练习4参考:**
class BankAccount {
private:
string accountNumber;
double balance;
public:
BankAccount(string num, double bal = 0)
: accountNumber(num), balance(bal) {}
void deposit(double amount) {
if (amount > 0) balance += amount;
}
bool withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
}
double getBalance() const { return balance; }
};
===== 下一章 =====
继续学习:[[第六章_继承与多态|第六章 继承与多态]]