本章将详细介绍C++的面向对象编程基础——类与对象,包括类的定义、构造函数、析构函数、this指针等核心概念。
类是C++中实现面向对象编程的基础,是用户自定义的数据类型,包含数据成员和成员函数。
#include <iostream> #include <string> 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; }
| 访问修饰符 | 类内部 | 派生类 | 外部 |
| ———– | ——– | ——– | —— |
| public | ✓ | ✓ | ✓ |
| protected | ✓ | ✓ | ✗ |
| private | ✓ | ✗ | ✗ |
#include <iostream> 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; } };
#include <iostream> 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; }
#include <iostream> #include <string> 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; }
#include <iostream> 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; }
#include <iostream> #include <string> 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; }
#include <iostream> #include <cstring> 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; }
#include <iostream> 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; }
#include <iostream> 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在这里析构(最后)
#include <iostream> 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; }
#include <iostream> 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; }
#include <iostream> 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; }
#include <iostream> 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; }
#include <iostream> 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; }
#include <iostream> 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; }
本章我们学习了:
基础练习:
1. 设计一个Book类,包含书名、作者、价格,提供相应的getter和setter
2. 实现一个计数器类,使用静态成员统计创建的对象数量
3. 编写一个字符串类MyString,实现构造函数和析构函数,管理动态内存
4. 实现一个BankAccount类,支持存款、取款、查询余额,确保余额不为负
进阶练习:
5. 设计一个矩阵类Matrix,支持基本的矩阵运算
6. 实现一个单向链表类LinkedList,包含插入、删除、查找操作
7. 创建一个日期类Date,支持日期计算(加减天数)
思考题:
8. 什么时候应该使用explicit关键字?举例说明
9. 分析以下代码的问题:
<code cpp>
String func() {
String s("Hello");
return s;
}
int main() {
String s2 = func();
}
</code>
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; } };
继续学习:第六章 继承与多态