C++ Primer Plus 第10章:对象和类

10.1 过程性编程与面向对象编程

10.1.1 两种编程范式的对比

复制代码
过程性编程(C风格):          面向对象编程(C++):
┌─────────────────┐           ┌─────────────────────┐
│   数据(变量)   │           │       类(Class)    │
│   +             │    →      │  ┌────────────────┐  │
│   函数(操作)   │           │  │ 数据(属性)   │  │
└─────────────────┘           │  │ 函数(方法)   │  │
                              │  └────────────────┘  │
                              └─────────────────────┘
数据和操作是分离的              数据和操作封装在一起

OOP 三大核心特性:

  • 封装(Encapsulation):将数据和操作绑定,隐藏实现细节
  • 继承(Inheritance):从已有类派生新类,复用代码
  • 多态(Polymorphism):同一接口,不同实现

10.2 类的基本概念

10.2.1 类的定义

cpp 复制代码
// stock.h -- 股票类的头文件
#ifndef STOCK_H_
#define STOCK_H_

#include <string>

class Stock   // 类定义
{
private:                    // 私有成员(外部不可直接访问)
    std::string company;    // 公司名称
    long        shares;     // 持股数量
    double      share_val;  // 每股价格
    double      total_val;  // 总价值

    void set_tot()          // 私有成员函数
    {
        total_val = shares * share_val;
    }

public:                     // 公有成员(外部可以访问)
    // 构造函数
    Stock(const std::string& co, long n, double pr);
    // 默认构造函数
    Stock();
    // 析构函数
    ~Stock();

    // 成员函数(方法)
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    void show() const;      // const成员函数:不修改对象

    // 访问器(getter)
    const std::string& getCompany() const { return company; }
    long   getShares()   const { return shares; }
    double getShareVal() const { return share_val; }
    double getTotalVal() const { return total_val; }
};

#endif

10.2.2 类的实现

cpp 复制代码
// stock.cpp -- 股票类的实现
#include <iostream>
#include "stock.h"

// 构造函数:使用初始化列表(推荐)
Stock::Stock(const std::string& co, long n, double pr)
    : company(co), shares(0), share_val(0), total_val(0)
{
    if (n < 0)
    {
        std::cout << "持股数量不能为负,设为0" << std::endl;
        shares = 0;
    }
    else
        shares = n;

    share_val = pr;
    set_tot();
    std::cout << "构造函数:创建 " << company << " 对象" << std::endl;
}

// 默认构造函数
Stock::Stock()
    : company("无名"), shares(0), share_val(0), total_val(0)
{
    std::cout << "默认构造函数被调用" << std::endl;
}

// 析构函数
Stock::~Stock()
{
    std::cout << "析构函数:销毁 " << company << " 对象" << std::endl;
}

// 买入股票
void Stock::buy(long num, double price)
{
    if (num < 0)
    {
        std::cout << "买入数量不能为负" << std::endl;
        return;
    }
    shares    += num;
    share_val  = price;
    set_tot();
}

// 卖出股票
void Stock::sell(long num, double price)
{
    using namespace std;
    if (num < 0)
    {
        cout << "卖出数量不能为负" << endl;
        return;
    }
    if (num > shares)
    {
        cout << "持股不足,无法卖出" << endl;
        return;
    }
    shares    -= num;
    share_val  = price;
    set_tot();
}

// 更新股价
void Stock::update(double price)
{
    share_val = price;
    set_tot();
}

// 显示信息(const成员函数)
void Stock::show() const
{
    using namespace std;
    cout << "公司:" << company << endl;
    cout << "持股:" << shares  << " 股" << endl;
    cout << "股价:" << share_val << " 元/股" << endl;
    cout << "总值:" << total_val << " 元" << endl;
}

10.2.3 使用类

cpp 复制代码
// usestock.cpp -- 使用Stock类
#include <iostream>
#include "stock.h"

int main()
{
    using namespace std;

    cout << "===== 创建股票对象 =====" << endl;

    // 方式1:调用有参构造函数
    Stock fluffy("腾讯控股", 100, 350.0);
    fluffy.show();

    cout << "\n===== 买入操作 =====" << endl;
    fluffy.buy(200, 360.0);
    fluffy.show();

    cout << "\n===== 卖出操作 =====" << endl;
    fluffy.sell(50, 380.0);
    fluffy.show();

    cout << "\n===== 更新股价 =====" << endl;
    fluffy.update(400.0);
    fluffy.show();

    // 方式2:默认构造函数
    Stock empty;
    empty.show();

    // 方式3:C++11 列表初始化
    Stock bayer = {"拜耳制药", 50, 120.0};

    cout << "\n===== 程序结束,对象销毁 =====" << endl;
    return 0;
}

输出:

复制代码
===== 创建股票对象 =====
构造函数:创建 腾讯控股 对象
公司:腾讯控股
持股:100 股
股价:350 元/股
总值:35000 元

===== 买入操作 =====
公司:腾讯控股
持股:300 股
股价:360 元/股
总值:108000 元
...
===== 程序结束,对象销毁 =====
析构函数:销毁 拜耳制药 对象
析构函数:销毁 无名 对象
析构函数:销毁 腾讯控股 对象

10.3 类的访问控制

10.3.1 public、private、protected

cpp 复制代码
// access_control.cpp -- 访问控制示例
#include <iostream>
#include <string>

class BankAccount
{
private:
    // 私有成员:只有类的成员函数可以访问
    std::string owner;
    double      balance;
    std::string password;

    // 私有辅助函数
    bool validatePassword(const std::string& pwd) const
    {
        return pwd == password;
    }

public:
    // 公有成员:任何代码都可以访问
    BankAccount(const std::string& name,
                double initial,
                const std::string& pwd)
        : owner(name), balance(initial), password(pwd) {}

    // 存款
    void deposit(double amount)
    {
        if (amount > 0)
            balance += amount;
    }

    // 取款(需要密码验证)
    bool withdraw(double amount, const std::string& pwd)
    {
        if (!validatePassword(pwd))
        {
            std::cout << "密码错误!" << std::endl;
            return false;
        }
        if (amount > balance)
        {
            std::cout << "余额不足!" << std::endl;
            return false;
        }
        balance -= amount;
        return true;
    }

    // 查询余额
    double getBalance() const { return balance; }
    std::string getOwner() const { return owner; }
};

int main()
{
    using namespace std;

    BankAccount acc("张三", 10000.0, "123456");

    // ✅ 可以访问public成员
    acc.deposit(5000);
    cout << "余额:" << acc.getBalance() << endl;   // 15000

    acc.withdraw(3000, "123456");
    cout << "取款后余额:" << acc.getBalance() << endl;   // 12000

    acc.withdraw(1000, "wrong");   // 密码错误

    // ❌ 不能访问private成员
    // acc.balance = 999999;   // 编译错误!
    // acc.password = "hack";  // 编译错误!

    return 0;
}

💡 访问控制总结

  • private:只有类自身的成员函数可以访问(默认)
  • public任何代码都可以访问
  • protected:类自身和派生类可以访问(继承章节详述)

10.3.2 struct 与 class 的区别

cpp 复制代码
// struct 默认成员是 public
struct MyStruct {
    int x;      // 默认 public
    int y;      // 默认 public
};

// class 默认成员是 private
class MyClass {
    int x;      // 默认 private
    int y;      // 默认 private
public:
    int z;      // 显式 public
};

int main()
{
    MyStruct s;
    s.x = 10;   // ✅ 可以访问

    MyClass c;
    // c.x = 10;  // ❌ 错误:x是private
    c.z = 30;   // ✅ 可以访问

    return 0;
}

10.4 构造函数

10.4.1 构造函数的特点

cpp 复制代码
// constructor_demo.cpp -- 构造函数详解
#include <iostream>
#include <string>

class Person
{
private:
    std::string name;
    int         age;
    double      height;

public:
    // 1. 默认构造函数(无参数)
    Person()
        : name("未知"), age(0), height(0.0)
    {
        std::cout << "默认构造函数" << std::endl;
    }

    // 2. 有参构造函数
    Person(const std::string& n, int a, double h)
        : name(n), age(a), height(h)
    {
        std::cout << "有参构造函数:" << name << std::endl;
    }

    // 3. 单参数构造函数(可用于隐式转换,加explicit防止)
    explicit Person(const std::string& n)
        : name(n), age(0), height(0.0)
    {
        std::cout << "单参数构造函数:" << name << std::endl;
    }

    void show() const
    {
        std::cout << "姓名:" << name
                  << " 年龄:" << age
                  << " 身高:" << height << std::endl;
    }
};

int main()
{
    using namespace std;

    Person p1;                          // 默认构造函数
    Person p2("李四", 25, 175.5);      // 有参构造函数
    Person p3(string("王五"));          // 单参数构造函数

    // explicit 防止隐式转换
    // Person p4 = "赵六";   // ❌ 错误:explicit阻止隐式转换
    Person p4 = Person(string("赵六")); // ✅ 显式转换

    p1.show();
    p2.show();
    p3.show();
    p4.show();

    return 0;
}

10.4.2 成员初始化列表

cpp 复制代码
// init_list.cpp -- 成员初始化列表
#include <iostream>
#include <string>

class Rectangle
{
private:
    const int   id;       // const成员必须用初始化列表
    int&        ref;      // 引用成员必须用初始化列表
    double      width;
    double      height;
    std::string label;

public:
    // 初始化列表:在函数体执行前初始化成员
    // 顺序应与成员声明顺序一致
    Rectangle(int i, int& r, double w, double h, const std::string& l)
        : id(i), ref(r), width(w), height(h), label(l)
    {
        // 此时成员已经初始化完毕
        std::cout << "创建矩形 #" << id << std::endl;
    }

    double area()   const { return width * height; }
    double perimeter() const { return 2 * (width + height); }

    void show() const
    {
        std::cout << "矩形 #" << id << " [" << label << "]"
                  << " 宽=" << width << " 高=" << height
                  << " 面积=" << area() << std::endl;
    }
};

int main()
{
    int refVal = 100;
    Rectangle r1(1, refVal, 5.0, 3.0, "客厅");
    Rectangle r2(2, refVal, 8.0, 4.0, "卧室");

    r1.show();
    r2.show();

    return 0;
}

💡 必须使用初始化列表的情况

  1. const 成员变量
  2. 引用(&)成员变量
  3. 没有默认构造函数的类类型成员
  4. 基类构造函数(继承时)

10.4.3 拷贝构造函数

cpp 复制代码
// copy_constructor.cpp -- 拷贝构造函数
#include <iostream>
#include <string>

class MyString
{
private:
    char* data;
    int   length;

public:
    // 普通构造函数
    MyString(const char* str = "")
    {
        length = strlen(str);
        data   = new char[length + 1];
        strcpy(data, str);
        std::cout << "构造:\"" << data << "\"" << std::endl;
    }

    // 拷贝构造函数(深拷贝)
    MyString(const MyString& other)
    {
        length = other.length;
        data   = new char[length + 1];   // 分配新内存
        strcpy(data, other.data);        // 复制内容
        std::cout << "拷贝构造:\"" << data << "\"" << std::endl;
    }

    // 析构函数
    ~MyString()
    {
        std::cout << "析构:\"" << data << "\"" << std::endl;
        delete[] data;
    }

    void show() const
    {
        std::cout << "字符串:\"" << data << "\" 长度:" << length << std::endl;
    }
};

int main()
{
    MyString s1("Hello");
    MyString s2 = s1;    // 调用拷贝构造函数
    MyString s3(s1);     // 同上

    s1.show();
    s2.show();
    s3.show();

    return 0;
}

⚠️ 浅拷贝 vs 深拷贝

  • 浅拷贝(默认):复制指针值,两个对象共享同一块内存,析构时会双重释放!
  • 深拷贝:分配新内存并复制内容,两个对象独立,安全。
  • 含有指针成员的类必须自定义拷贝构造函数实现深拷贝。

10.5 析构函数

cpp 复制代码
// destructor_demo.cpp -- 析构函数详解
#include <iostream>
#include <string>

class Resource
{
private:
    std::string name;
    int*        data;
    int         size;

public:
    Resource(const std::string& n, int sz)
        : name(n), size(sz)
    {
        data = new int[size];   // 分配资源
        for (int i = 0; i < size; i++)
            data[i] = i * 10;
        std::cout << "[" << name << "] 资源已分配(" << size << "个int)" << std::endl;
    }

    // 析构函数:释放资源
    ~Resource()
    {
        delete[] data;   // 释放动态内存
        std::cout << "[" << name << "] 资源已释放" << std::endl;
    }

    void show() const
    {
        std::cout << "[" << name << "] 数据:";
        for (int i = 0; i < size; i++)
            std::cout << data[i] << " ";
        std::cout << std::endl;
    }
};

void demoScope()
{
    std::cout << "--- 进入函数 ---" << std::endl;
    Resource r("函数内资源", 3);   // 构造
    r.show();
    std::cout << "--- 离开函数 ---" << std::endl;
}   // r 在这里自动析构

int main()
{
    std::cout << "=== 程序开始 ===" << std::endl;

    demoScope();   // 函数内的对象自动析构

    std::cout << "\n--- 动态分配 ---" << std::endl;
    Resource* p = new Resource("堆上资源", 5);
    p->show();
    delete p;   // 必须手动析构!

    std::cout << "\n=== 程序结束 ===" << std::endl;
    return 0;
}

输出:

复制代码
=== 程序开始 ===
--- 进入函数 ---
[函数内资源] 资源已分配(3个int)
[函数内资源] 数据:0 10 20
--- 离开函数 ---
[函数内资源] 资源已释放

--- 动态分配 ---
[堆上资源] 资源已分配(5个int)
[堆上资源] 数据:0 10 20 30 40
[堆上资源] 资源已释放

=== 程序结束 ===

10.6 const 成员函数

cpp 复制代码
// const_member.cpp -- const成员函数
#include <iostream>

class Circle
{
private:
    double radius;

public:
    Circle(double r) : radius(r) {}

    // const成员函数:承诺不修改对象的任何成员
    double getRadius() const { return radius; }
    double area()      const { return 3.14159 * radius * radius; }
    double perimeter() const { return 2 * 3.14159 * radius; }

    // 非const成员函数:可以修改成员
    void setRadius(double r)
    {
        if (r > 0) radius = r;
    }

    void show() const
    {
        std::cout << "半径:" << radius
                  << " 面积:" << area()
                  << " 周长:" << perimeter() << std::endl;
    }
};

int main()
{
    Circle c1(5.0);
    c1.show();
    c1.setRadius(8.0);
    c1.show();

    // const对象只能调用const成员函数
    const Circle c2(3.0);
    c2.show();           // ✅ const函数
    c2.getRadius();      // ✅ const函数
    // c2.setRadius(4.0); // ❌ 错误:const对象不能调用非const函数

    return 0;
}

💡 const成员函数规则

  • 在函数声明和定义末尾加 const
  • const 对象只能调用 const 成员函数
  • const 成员函数不能修改 成员变量(除非成员是 mutable
  • 建议:所有不修改对象的成员函数都加 const

10.7 this 指针

cpp 复制代码
// this_pointer.cpp -- this指针示例
#include <iostream>
#include <string>

class Builder
{
private:
    std::string name;
    int         age;
    std::string city;

public:
    Builder() : name(""), age(0), city("") {}

    // 返回 *this 实现链式调用
    Builder& setName(const std::string& n)
    {
        this->name = n;   // this->name 等价于 name
        return *this;     // 返回当前对象的引用
    }

    Builder& setAge(int a)
    {
        age = a;
        return *this;
    }

    Builder& setCity(const std::string& c)
    {
        city = c;
        return *this;
    }

    void show() const
    {
        std::cout << "姓名:" << name
                  << " 年龄:" << age
                  << " 城市:" << city << std::endl;
    }

    // this用于区分同名参数和成员
    void setInfo(std::string name, int age)
    {
        this->name = name;   // this->name是成员,name是参数
        this->age  = age;
    }
};

// 比较两个对象,返回较大的那个
class Value
{
public:
    int val;
    Value(int v) : val(v) {}

    const Value& max(const Value& other) const
    {
        return (val > other.val) ? *this : other;
    }
};

int main()
{
    using namespace std;

    // 链式调用(Builder模式)
    Builder b;
    b.setName("张三").setAge(25).setCity("北京");   // 链式调用
    b.show();

    // this用于比较
    Value v1(10), v2(20);
    const Value& bigger = v1.max(v2);
    cout << "较大值:" << bigger.val << endl;   // 20

    return 0;
}

10.8 对象数组

cpp 复制代码
// object_array.cpp -- 对象数组示例
#include <iostream>
#include <string>

class Student
{
private:
    std::string name;
    int         score;

public:
    // 默认构造函数(对象数组必须有)
    Student() : name("未知"), score(0) {}

    Student(const std::string& n, int s)
        : name(n), score(s) {}

    void setInfo(const std::string& n, int s)
    {
        name = n; score = s;
    }

    void show() const
    {
        std::cout << "姓名:" << name
                  << " 成绩:" << score << std::endl;
    }

    int getScore() const { return score; }
    const std::string& getName() const { return name; }
};

int main()
{
    using namespace std;

    // 方式1:默认构造函数创建数组
    Student class1[3];
    class1[0].setInfo("张三", 85);
    class1[1].setInfo("李四", 92);
    class1[2].setInfo("王五", 78);

    // 方式2:初始化列表
    Student class2[3] = {
        {"赵六", 90},
        {"钱七", 88},
        {"孙八", 95}
    };

    cout << "班级1:" << endl;
    for (int i = 0; i < 3; i++)
        class1[i].show();

    cout << "\n班级2:" << endl;
    for (int i = 0; i < 3; i++)
        class2[i].show();

    // 找最高分
    int best = 0;
    for (int i = 1; i < 3; i++)
        if (class2[i].getScore() > class2[best].getScore())
            best = i;
    cout << "\n最高分:" << class2[best].getName()
         << "(" << class2[best].getScore() << "分)" << endl;

    // 动态对象数组
    int n = 2;
    Student* dynamic = new Student[n];
    dynamic[0].setInfo("动态1", 80);
    dynamic[1].setInfo("动态2", 85);
    for (int i = 0; i < n; i++)
        dynamic[i].show();
    delete[] dynamic;

    return 0;
}

10.9 类作用域

cpp 复制代码
// class_scope.cpp -- 类作用域示例
#include <iostream>

class MyClass
{
public:
    // 类作用域内的枚举(C++11推荐用enum class)
    enum Color { RED, GREEN, BLUE };
    enum class Size { SMALL, MEDIUM, LARGE };   // 强类型枚举

    // 类内静态常量(C++11)
    static const int MAX_COUNT = 100;
    static constexpr double PI = 3.14159;

    // 类内类型别名
    using ValueType = double;

private:
    Color     color;
    Size      size;
    ValueType value;

public:
    MyClass(Color c, Size s, ValueType v)
        : color(c), size(s), value(v) {}

    void show() const
    {
        std::cout << "颜色:" << color
                  << " 大小:" << static_cast<int>(size)
                  << " 值:" << value << std::endl;
    }
};

// 静态成员在类外初始化(非const静态成员)
// int MyClass::MAX_COUNT = 100;  // 如果不是const

int main()
{
    using namespace std;

    // 访问类作用域内的枚举
    MyClass obj(MyClass::RED, MyClass::Size::LARGE, 3.14);
    obj.show();

    cout << "MAX_COUNT = " << MyClass::MAX_COUNT << endl;
    cout << "PI = " << MyClass::PI << endl;

    return 0;
}

10.10 综合示例:完整的银行账户类

cpp 复制代码
// bank_account.cpp -- 综合示例:银行账户类
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>

class Transaction
{
public:
    enum class Type { DEPOSIT, WITHDRAW, TRANSFER };

    Type        type;
    double      amount;
    std::string description;

    Transaction(Type t, double a, const std::string& desc)
        : type(t), amount(a), description(desc) {}

    void show() const
    {
        std::string typeStr;
        switch (type)
        {
            case Type::DEPOSIT:  typeStr = "存款"; break;
            case Type::WITHDRAW: typeStr = "取款"; break;
            case Type::TRANSFER: typeStr = "转账"; break;
        }
        std::cout << std::setw(6) << typeStr
                  << " | " << std::setw(10) << amount
                  << " | " << description << std::endl;
    }
};

class BankAccount
{
private:
    std::string              owner;
    std::string              accountNo;
    double                   balance;
    std::vector<Transaction> history;

    static int accountCounter;   // 静态成员:所有对象共享

    void addHistory(Transaction::Type type,
                    double amount,
                    const std::string& desc)
    {
        history.emplace_back(type, amount, desc);
    }

public:
    BankAccount(const std::string& name, double initial = 0.0)
        : owner(name), balance(initial)
    {
        accountNo = "ACC" + std::to_string(++accountCounter);
        if (initial > 0)
            addHistory(Transaction::Type::DEPOSIT, initial, "开户存款");
        std::cout << "账户创建:" << accountNo
                  << " 户主:" << owner << std::endl;
    }

    ~BankAccount()
    {
        std::cout << "账户注销:" << accountNo << std::endl;
    }

    // 存款
    bool deposit(double amount, const std::string& desc = "存款")
    {
        if (amount <= 0)
        {
            std::cout << "存款金额必须大于0" << std::endl;
            return false;
        }
        balance += amount;
        addHistory(Transaction::Type::DEPOSIT, amount, desc);
        return true;
    }

    // 取款
    bool withdraw(double amount, const std::string& desc = "取款")
    {
        if (amount <= 0)
        {
            std::cout << "取款金额必须大于0" << std::endl;
            return false;
        }
        if (amount > balance)
        {
            std::cout << "余额不足!当前余额:" << balance << std::endl;
            return false;
        }
        balance -= amount;
        addHistory(Transaction::Type::WITHDRAW, amount, desc);
        return true;
    }

    // 转账
    bool transfer(BankAccount& target, double amount)
    {
        std::string desc = "转账至" + target.accountNo;
        if (withdraw(amount, desc))
        {
            target.deposit(amount, "来自" + accountNo + "的转账");
            return true;
        }
        return false;
    }

    // 查询
    double      getBalance()   const { return balance; }
    std::string getOwner()     const { return owner; }
    std::string getAccountNo() const { return accountNo; }

    // 打印账单
    void printStatement() const
    {
        using namespace std;
        cout << "\n===== 账户账单 =====" << endl;
        cout << "账号:" << accountNo << " 户主:" << owner << endl;
        cout << string(45, '-') << endl;
        cout << setw(6) << "类型"
             << " | " << setw(10) << "金额"
             << " | " << "说明" << endl;
        cout << string(45, '-') << endl;
        for (const auto& t : history)
            t.show();
        cout << string(45, '-') << endl;
        cout << "当前余额:" << fixed << setprecision(2)
             << balance << " 元" << endl;
    }

    static int getAccountCount() { return accountCounter; }
};

// 静态成员在类外初始化
int BankAccount::accountCounter = 0;

int main()
{
    using namespace std;

    cout << "===== 银行系统演示 =====" << endl;

    BankAccount alice("张三", 10000.0);
    BankAccount bob("李四", 5000.0);

    cout << "\n--- 操作记录 ---" << endl;
    alice.deposit(3000.0, "工资");
    alice.withdraw(500.0, "购物");
    alice.transfer(bob, 2000.0);
    bob.withdraw(1000.0, "房租");

    alice.printStatement();
    bob.printStatement();

    cout << "\n当前账户总数:" << BankAccount::getAccountCount() << endl;

    return 0;
}

输出(部分):

复制代码
===== 银行系统演示 =====
账户创建:ACC1 户主:张三
账户创建:ACC2 户主:李四

--- 操作记录 ---

===== 账户账单 =====
账号:ACC1 户主:张三
---------------------------------------------
类型 |       金额 | 说明
---------------------------------------------
  存款 |      10000 | 开户存款
  存款 |       3000 | 工资
  取款 |        500 | 购物
  取款 |       2000 | 转账至ACC2
---------------------------------------------
当前余额:10500.00 元

===== 账户账单 =====
账号:ACC2 户主:李四
---------------------------------------------
  存款 |       5000 | 开户存款
  存款 |       2000 | 来自ACC1的转账
  取款 |       1000 | 房租
---------------------------------------------
当前余额:6000.00 元

当前账户总数:2

📝 第10章知识点总结

知识点 核心要点
类的定义 class 关键字,包含数据成员和成员函数,默认 private
访问控制 private(类内)/ public(任意)/ protected(类内+派生类)
构造函数 与类同名,无返回值,对象创建时自动调用,可重载
初始化列表 构造函数名() : 成员1(值1), 成员2(值2) {},const/引用成员必须用
析构函数 ~类名(),对象销毁时自动调用,释放资源
拷贝构造函数 类名(const 类名& other),含指针成员必须深拷贝
const成员函数 函数末尾加 const,不修改成员,const对象只能调用const函数
this指针 指向当前对象,用于区分同名参数/成员,返回 *this 实现链式调用
static成员 所有对象共享,类外初始化,用 类名:: 访问
explicit 防止单参数构造函数的隐式类型转换
对象数组 需要默认构造函数,可用初始化列表
struct vs class struct默认public,class默认private,其余相同
相关推荐
不会C语言的男孩2 小时前
C++ Primer Plus 第11章:使用类
开发语言·c++
yujunl2 小时前
NetCore常用的中间件说明
开发语言
comedate3 小时前
FMT_UNICODE 与 CUDA 编码配置专栏技术文档
c++·utf-8·nvcc
玖玥拾3 小时前
C/C++ 基础笔记(二)
c语言·c++
Hanniel3 小时前
Python 元类(下):进阶与实战建议
开发语言·python
会编程的土豆3 小时前
Go interface 底层的 itab 到底是什么
开发语言·后端·golang
千纸鹤の脉搏3 小时前
多线程的初步了解---进程与线程
java·开发语言·学习·线程
秋田君3 小时前
Qt 5.12.8 下载与安装教程(附网盘资源)
开发语言·qt
故事和你913 小时前
洛谷-【动态规划2】线性状态动态规划4
开发语言·数据结构·c++·算法·动态规划·图论