Skip to content

面向对象基础

面向对象编程(OOP)是C++的核心特性之一。本章将介绍类与对象、构造函数、析构函数、成员函数、访问控制等面向对象的基础概念。

类与对象

类的定义

cpp
#include <iostream>
#include <string>
using namespace std;

// 类的定义
// class 类名 { 成员 };

class Student {
    // 访问修饰符
public:     // 公有成员,可以在类外部访问
    // 数据成员(属性)
    string name;
    int age;
    double score;
    
    // 成员函数(方法)
    void display() {
        cout << "姓名: " << name << endl;
        cout << "年龄: " << age << endl;
        cout << "分数: " << score << endl;
    }
    
    // 成员函数可以在类内定义,也可以在类外定义
    void setInfo(string n, int a, double s);
    
private:    // 私有成员,只能在类内部访问
    string id;  // 学号
    
protected:  // 保护成员,只能在类内部和派生类中访问
    string secret;
};

// 在类外定义成员函数
// 返回类型 类名::函数名(参数列表) { 函数体 }
void Student::setInfo(string n, int a, double s) {
    name = n;
    age = a;
    score = s;
}

int main() {
    // 创建对象
    Student stu1;  // 默认构造
    
    // 访问公有成员
    stu1.name = "张三";
    stu1.age = 20;
    stu1.score = 95.5;
    
    // 调用成员函数
    stu1.display();
    
    // 使用成员函数设置信息
    Student stu2;
    stu2.setInfo("李四", 22, 88.0);
    stu2.display();
    
    // 不能访问私有成员
    // stu2.id = "001";  // 错误:id是私有的
    
    return 0;
}

构造函数

cpp
#include <iostream>
#include <string>
using namespace std;

class Rectangle {
private:
    double width;
    double height;
    
public:
    // ============ 默认构造函数 ============
    
    // 无参构造函数
    Rectangle() {
        width = 1.0;
        height = 1.0;
        cout << "默认构造函数被调用" << endl;
    }
    
    // ============ 带参数的构造函数 ============
    
    // 普通参数构造
    Rectangle(double w, double h) {
        width = w;
        height = h;
        cout << "带参数构造函数被调用" << endl;
    }
    
    // 单参数构造(可能隐式转换)
    Rectangle(double size) {
        width = size;
        height = size;
        cout << "单参数构造函数被调用" << endl;
    }
    
    // ============ 委托构造函数(C++11) ============
    
    // 一个构造函数调用另一个构造函数
    Rectangle(int size) : Rectangle((double)size, (double)size) {
        cout << "委托构造函数被调用" << endl;
    }
    
    // ============ 拷贝构造函数 ============
    
    Rectangle(const Rectangle& other) {
        width = other.width;
        height = other.height;
        cout << "拷贝构造函数被调用" << endl;
    }
    
    // ============ 移动构造函数(C++11) ============
    
    Rectangle(Rectangle&& other) noexcept {
        width = other.width;
        height = other.height;
        other.width = 0;
        other.height = 0;
        cout << "移动构造函数被调用" << endl;
    }
    
    // ============ 成员函数 ============
    
    double area() {
        return width * height;
    }
    
    void display() {
        cout << "宽: " << width << ", 高: " << height << endl;
    }
};

int main() {
    // 调用不同的构造函数
    cout << "===== 创建对象 =====" << endl;
    
    Rectangle r1;           // 默认构造
    Rectangle r2(3.0, 4.0); // 带参数构造
    Rectangle r3(5.0);      // 单参数构造
    Rectangle r4(6);        // 委托构造
    
    r1.display();
    r2.display();
    r3.display();
    r4.display();
    
    // 拷贝构造
    cout << "\n===== 拷贝构造 =====" << endl;
    Rectangle r5 = r2;      // 拷贝构造
    Rectangle r6(r2);       // 拷贝构造
    
    // 移动构造
    cout << "\n===== 移动构造 =====" << endl;
    Rectangle r7 = move(r2);  // 移动构造
    
    // 隐式转换(可能不期望)
    cout << "\n===== 隐式转换 =====" << endl;
    Rectangle r8 = 10.0;    // 隐式调用单参数构造
    
    // 使用explicit防止隐式转换
    // explicit Rectangle(double size);  // 加在声明前
    
    return 0;
}

成员初始化列表

cpp
#include <iostream>
#include <string>
using namespace std;

class Person {
private:
    string name;
    int age;
    const int id;        // const成员必须在初始化列表初始化
    int& ref;            // 引用成员必须在初始化列表初始化
    
public:
    // 使用成员初始化列表
    // 比在构造函数体内赋值更高效
    Person(string n, int a, int i, int& r) 
        : name(n), age(a), id(i), ref(r)  // 初始化列表
    {
        cout << "Person构造函数" << endl;
    }
    
    // 初始化列表的顺序由成员声明的顺序决定,不是初始化列表的顺序
    // 建议:初始化列表顺序与成员声明顺序一致
    
    void display() {
        cout << "姓名: " << name << endl;
        cout << "年龄: " << age << endl;
        cout << "ID: " << id << endl;
        cout << "引用: " << ref << endl;
    }
};

class Student {
private:
    string name;
    int scores[3];  // 数组成员
    
public:
    // 数组成员的初始化
    Student(string n, int s1, int s2, int s3) 
        : name(n), scores{s1, s2, s3}  // C++11数组初始化
    {
        cout << "Student构造函数" << endl;
    }
    
    void display() {
        cout << "姓名: " << name << endl;
        cout << "成绩: ";
        for (int s : scores) {
            cout << s << " ";
        }
        cout << endl;
    }
};

class Base {
public:
    Base(int value) {
        cout << "Base构造: " << value << endl;
    }
};

class Derived : public Base {
private:
    int data;
    
public:
    // 先调用基类构造,再初始化成员
    Derived(int v) : Base(v), data(v) {
        cout << "Derived构造" << endl;
    }
};

int main() {
    int value = 100;
    
    Person p("张三", 25, 1, value);
    p.display();
    
    cout << endl;
    
    Student s("李四", 90, 85, 95);
    s.display();
    
    cout << endl;
    
    Derived d(42);
    
    return 0;
}

析构函数

cpp
#include <iostream>
#include <string>
using namespace std;

class Resource {
private:
    string name;
    int* data;  // 动态分配的资源
    
public:
    // 构造函数
    Resource(string n) : name(n) {
        data = new int[100];  // 分配资源
        cout << "构造: " << name << endl;
    }
    
    // 析构函数
    // 对象销毁时自动调用
    // 用于释放资源
    ~Resource() {
        delete[] data;  // 释放资源
        cout << "析构: " << name << endl;
    }
    
    void use() {
        cout << "使用资源: " << name << endl;
    }
};

class Container {
private:
    Resource* res;
    
public:
    Container() {
        res = new Resource("容器资源");
        cout << "Container构造" << endl;
    }
    
    ~Container() {
        delete res;  // 释放内部资源
        cout << "Container析构" << endl;
    }
};

// 函数内创建对象
void testFunction() {
    cout << "===== 函数开始 =====" << endl;
    
    Resource local("局部对象");
    local.use();
    
    cout << "===== 函数结束 =====" << endl;
    // local在这里被销毁
}

int main() {
    // 局部对象
    cout << "===== 局部对象 =====" << endl;
    {
        Resource r1("对象1");
        Resource r2("对象2");
        r1.use();
        r2.use();
    }  // r2先析构,r1后析构(后构造的先析构)
    
    cout << "\n===== 动态对象 =====" << endl;
    Resource* ptr = new Resource("动态对象");
    ptr->use();
    delete ptr;  // 手动释放,调用析构函数
    
    cout << "\n===== 函数调用 =====" << endl;
    testFunction();
    
    cout << "\n===== 包含资源的对象 =====" << endl;
    {
        Container c;
    }  // c析构时自动释放内部资源
    
    return 0;
}

访问控制

cpp
#include <iostream>
#include <string>
using namespace std;

class BankAccount {
private:    // 私有成员:只能在类内部访问
    string accountNumber;
    double balance;
    string password;
    
    // 私有成员函数
    bool verifyPassword(string pwd) {
        return pwd == password;
    }
    
protected:  // 保护成员:类内部和派生类可访问
    string ownerName;
    
public:     // 公有成员:任何地方都可访问
    // 构造函数
    BankAccount(string owner, string accNum, string pwd, double initial) 
        : ownerName(owner), accountNumber(accNum), password(pwd), balance(initial) {}
    
    // 公有接口函数(getter)
    string getOwner() const {
        return ownerName;
    }
    
    string getAccountNumber() const {
        return accountNumber;
    }
    
    double getBalance() const {
        return balance;
    }
    
    // 公有接口函数(setter)
    bool setPassword(string oldPwd, string newPwd) {
        if (verifyPassword(oldPwd)) {
            password = newPwd;
            return true;
        }
        return false;
    }
    
    // 存款
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            cout << "存款成功: " << amount << endl;
        }
    }
    
    // 取款
    bool withdraw(double amount, string pwd) {
        if (!verifyPassword(pwd)) {
            cout << "密码错误" << endl;
            return false;
        }
        
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            cout << "取款成功: " << amount << endl;
            return true;
        }
        
        cout << "余额不足或金额无效" << endl;
        return false;
    }
    
    // 显示账户信息
    void displayInfo() {
        cout << "户主: " << ownerName << endl;
        cout << "账号: " << accountNumber << endl;
        cout << "余额: " << balance << endl;
    }
};

// 派生类可以访问保护成员
class SavingsAccount : public BankAccount {
private:
    double interestRate;
    
public:
    SavingsAccount(string owner, string accNum, string pwd, double initial, double rate)
        : BankAccount(owner, accNum, pwd, initial), interestRate(rate) {}
    
    void applyInterest() {
        double interest = getBalance() * interestRate;
        deposit(interest);
        cout << "利息已入账: " << interest << endl;
    }
    
    // 可以访问保护成员
    void displayOwner() {
        cout << "账户持有人: " << ownerName << endl;
    }
};

int main() {
    BankAccount account("张三", "1234567890", "1234", 1000.0);
    
    // 公有成员可以直接访问
    account.displayInfo();
    
    // 通过公有接口访问私有数据
    cout << "\n当前余额: " << account.getBalance() << endl;
    
    // 存款
    account.deposit(500.0);
    cout << "存款后余额: " << account.getBalance() << endl;
    
    // 取款
    account.withdraw(200.0, "1234");
    cout << "取款后余额: " << account.getBalance() << endl;
    
    // 错误的密码
    account.withdraw(100.0, "wrong");
    
    // 不能直接访问私有成员
    // account.balance = 0;  // 错误
    // account.password = "new";  // 错误
    
    // 不能直接访问保护成员
    // account.ownerName = "李四";  // 错误
    
    cout << "\n===== 储蓄账户 =====" << endl;
    SavingsAccount savings("李四", "9876543210", "5678", 5000.0, 0.03);
    savings.displayOwner();
    savings.applyInterest();
    
    return 0;
}

静态成员

cpp
#include <iostream>
#include <string>
using namespace std;

class Counter {
private:
    int value;
    
    // 静态数据成员:所有对象共享
    static int count;  // 声明
    
public:
    Counter() : value(0) {
        count++;  // 每创建一个对象,count加1
    }
    
    ~Counter() {
        count--;  // 每销毁一个对象,count减1
    }
    
    // 静态成员函数:只能访问静态成员
    static int getCount() {
        // value = 10;  // 错误:不能访问非静态成员
        return count;
    }
    
    // 常量静态成员(C++17前需要在类外定义)
    static const int MAX_VALUE = 100;
    
    // C++11:constexpr静态成员
    static constexpr double PI = 3.14159;
    
    void display() {
        cout << "value = " << value << endl;
    }
};

// 静态成员的定义和初始化(在类外)
int Counter::count = 0;

class Singleton {
private:
    static Singleton* instance;
    
    // 私有构造函数
    Singleton() {
        cout << "Singleton创建" << endl;
    }
    
public:
    // 禁止拷贝
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    
    // 获取唯一实例
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
    
    void doSomething() {
        cout << "Singleton工作" << endl;
    }
};

Singleton* Singleton::instance = nullptr;

int main() {
    cout << "初始count: " << Counter::getCount() << endl;
    
    {
        Counter c1;
        cout << "创建c1后count: " << Counter::getCount() << endl;
        
        Counter c2;
        cout << "创建c2后count: " << Counter::getCount() << endl;
        
        Counter c3;
        cout << "创建c3后count: " << Counter::getCount() << endl;
    }
    
    cout << "离开作用域后count: " << Counter::getCount() << endl;
    
    // 访问静态常量
    cout << "\nMAX_VALUE: " << Counter::MAX_VALUE << endl;
    cout << "PI: " << Counter::PI << endl;
    
    // 单例模式
    cout << "\n===== 单例模式 =====" << endl;
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    
    cout << "s1 == s2: " << (s1 == s2) << endl;  // true
    
    s1->doSomething();
    
    return 0;
}

友元

cpp
#include <iostream>
#include <string>
using namespace std;

class Vector;  // 前向声明

class Point {
private:
    double x, y;
    
public:
    Point(double x = 0, double y = 0) : x(x), y(y) {}
    
    void display() {
        cout << "(" << x << ", " << y << ")" << endl;
    }
    
    // 声明友元函数
    friend Point add(const Point& a, const Point& b);
    
    // 声明友元类
    friend class Vector;
    
    // 声明另一个类的成员函数为友元
    friend void transform(Point& p, const Vector& v);
};

// 友元函数:可以访问类的私有成员
Point add(const Point& a, const Point& b) {
    return Point(a.x + b.x, a.y + b.y);  // 可以访问私有成员
}

class Vector {
private:
    double dx, dy;
    
public:
    Vector(double dx = 0, double dy = 0) : dx(dx), dy(dy) {}
    
    // 友元类的所有成员函数都可以访问Point的私有成员
    Point move(const Point& p) {
        return Point(p.x + dx, p.y + dy);  // 可以访问Point的私有成员
    }
    
    void display() {
        cout << "Vector(" << dx << ", " << dy << ")" << endl;
    }
};

// 另一个类的成员函数作为友元
void transform(Point& p, const Vector& v) {
    p.x += v.dx;
    p.y += v.dy;
}

int main() {
    Point p1(1, 2);
    Point p2(3, 4);
    
    cout << "p1: ";
    p1.display();
    cout << "p2: ";
    p2.display();
    
    // 使用友元函数
    Point p3 = add(p1, p2);
    cout << "\np1 + p2 = ";
    p3.display();
    
    // 使用友元类
    Vector v(10, 20);
    Point p4 = v.move(p1);
    cout << "\np1移动后: ";
    p4.display();
    
    // 使用友元成员函数
    transform(p1, v);
    cout << "p1变换后: ";
    p1.display();
    
    return 0;
}

本章小结

本章学习了:

  • 类与对象:类的定义、对象的创建和使用
  • 构造函数:默认构造、带参构造、拷贝构造、移动构造
  • 成员初始化列表:高效初始化成员
  • 析构函数:释放资源
  • 访问控制:public、private、protected
  • 静态成员:静态数据成员和静态成员函数
  • 友元:友元函数和友元类

下一章,我们将学习面向对象进阶,了解继承、多态和虚函数。