一、核心概念:类与对象的本质

  • 类:C++的核心抽象机制,是数据(成员变量)和操作(成员函数)的封装体,相当于“对象的模板”,定义对象的共同属性和行为。
  • 对象:类的实例化结果(占用实际内存),一个类可创建多个对象,各对象共享类的成员函数,但拥有独立的成员变量。
  • 类比:类=“汽车设计图纸”,对象=“具体的一辆汽车”(图纸不占空间,汽车占空间)。

二、类的定义与访问控制

  1. 类的定义语法(struct与class的区别)
// 1. class关键字(默认访问权限private)
class Car {
private:  // 私有成员(仅类内可访问)
    string brand;  // 成员变量(属性)
    int speed;
public:   // 公有成员(类内+类外可访问)
    // 成员函数(行为)
    void setInfo(string b, int s) {  // 赋值函数
        brand = b;
        speed = s;
    }
    void showInfo() {  // 展示函数
        cout << "品牌:" << brand << ",速度:" << speed << "km/h" << endl;
    }
protected:  // 保护成员(类内+子类可访问)
    int weight;
};




// 2. struct关键字(默认访问权限public,兼容C语言结构体)
struct Student {
    string name;  // 默认public
    int age;
    void show() {
        cout << "姓名:" << name << ",年龄:" << age << endl;
    }
};
  1. 访问权限控制(3种关键字)
权限关键字 访问范围 核心用途
private 仅类内可访问 封装核心数据,避免外部直接修改(如汽车的发动机参数)
public 类内+类外可访问 提供对外接口(如setter/getter函数、功能函数)
protected 类内+子类可访问 用于继承,让子类复用父类成员(如动物类的“呼吸”方法)

三、对象的创建与初始化

  1. 对象的3种创建方式
// 方式1:栈上创建(自动释放内存,常用)
Car c1;
c1.setInfo("奔驰", 120);
c1.showInfo();

// 方式2:堆上创建(new关键字,手动释放delete)
Car* c2 = new Car();
c2->setInfo("宝马", 150);  // 指针用->访问成员
c2->showInfo();
delete c2;  // 必须手动释放,避免内存泄漏

// 方式3:直接初始化(调用构造函数)
Car c3("奥迪", 180);  // 需配合带参构造函数使用
  1. 构造函数(对象初始化的核心)
  • 作用:对象创建时自动调用,初始化成员变量(默认无参构造函数)。
  • 语法规则:
  1. 函数名与类名完全一致,无返回值(连void都不写);
  2. 可重载(多个构造函数,参数列表不同);
  3. 若用户未定义,编译器自动生成“默认无参构造函数”(空实现)。
class Car {
private:
    string brand;
    int speed;
public:
    // 1. 无参构造函数(默认构造)
    Car() {
        brand = "未知品牌";
        speed = 0;
    }
    // 2. 带参构造函数(重载)
    Car(string b, int s) {
        brand = b;
        speed = s;
    }
    // 3. 拷贝构造函数(用已有对象初始化新对象)
    Car(const Car& other) {  // const避免修改原对象,&避免值拷贝
        brand = other.brand;
        speed = other.speed;
    }
};

// 调用示例
Car c1;  // 无参构造
Car c2("特斯拉", 200);  // 带参构造
Car c3 = c2;  // 拷贝构造(等价于Car c3(c2))
  1. 析构函数(对象销毁时清理资源)
  • 作用:对象释放时自动调用,释放堆内存、关闭文件等(如new的对象)。
  • 语法规则:
  1. 函数名前加 ~ ,与类名一致,无返回值、无参数;
  2. 不可重载(仅1个析构函数);
  3. 若用户未定义,编译器自动生成默认析构函数(空实现)。
class Car {
private:
    string* brand;  // 堆上的字符串(需手动释放)
public:
    // 构造函数(new分配内存)
    Car(string b) {
        brand = new string(b);  // 堆内存分配
    }
    // 析构函数(delete释放内存)
    ~Car() {
        delete brand;  // 必须手动释放,避免内存泄漏
        cout << "析构函数调用,内存已释放" << endl;
    }
};

四、类的核心特性:封装、继承、多态

  1. 封装(数据隐藏与接口暴露)
  • 核心思想:将成员变量设为 private ,通过 public 的成员函数(setter/getter)访问和修改,避免外部直接操作数据。
  • 实操示例:
class Person {
private:
    int age;  // 私有成员,外部不可直接修改
public:
    // setter函数(设置值,可加逻辑校验)
    void setAge(int a) {
        if (a >= 0 && a <= 120) {  // 校验年龄合法性
            age = a;
        } else {
            cout << "年龄输入错误!" << endl;
        }
    }
    // getter函数(获取值)
    int getAge() {
        return age;
    }
};

// 外部访问
Person p;
p.setAge(20);  // 正确:通过setter设置
cout << p.getAge() << endl;  // 正确:通过getter获取
// p.age = 30;  // 错误:private成员不可直接访问
  1. 继承(代码复用)
  • 核心思想:子类(派生类)继承父类(基类)的成员变量和成员函数,同时可添加新成员或重写父类函数。
  • 语法与关键规则:
// 父类(基类)
class Animal {
protected:
    string name;
public:
    void eat() {
        cout << name << "在吃东西" << endl;
    }
};

// 子类(派生类):public继承(常用)
class Dog : public Animal {
private:
    string color;
public:
    // 子类构造函数(需初始化父类成员)
    Dog(string n, string c) {
        name = n;  // 继承protected成员,可直接访问
        color = c;
    }
    // 重写父类函数(多态基础)
    void eat() {
        cout << color << "的" << name << "在吃骨头" << endl;
    }
    // 新增子类独有的函数
    void bark() {
        cout << name << "在汪汪叫" << endl;
    }
};

// 调用示例
Dog d("旺财", "黄色");
d.eat();  // 调用子类重写的eat()
d.bark();  // 调用子类新增的bark()
  • 继承权限(3种方式):
    继承方式 父类public成员 父类protected成员 父类private成员
    public 子类public 子类protected 不可访问
    protected 子类protected 子类protected 不可访问
    private 子类private 子类private 不可访问
  1. 多态(一个接口,多种实现)
  • 核心思想:父类指针/引用指向子类对象时,调用同名函数会执行子类的重写版本(需配合 virtual 关键字)。
  • 关键条件:
  1. 父类函数声明为 virtual (虚函数);
  2. 子类重写该虚函数(函数名、参数列表、返回值完全一致);
  3. 通过父类指针/引用调用函数。
class Animal {
public:
    // 虚函数(加virtual)
    virtual void makeSound() {
        cout << "动物在发出声音" << endl;
    }
};

class Cat : public Animal {
public:
    // 重写虚函数
    void makeSound() override {  // override关键字(C++11+),显式声明重写
        cout << "猫咪在喵喵叫" << endl;
    }
};

class Dog : public Animal {
public:
    void makeSound() override {
        cout << "小狗在汪汪叫" << endl;
    }
};

// 多态调用(核心)
void animalSound(Animal& a) {  // 父类引用
    a.makeSound();  // 调用子类重写的函数
}

// 测试
Cat c;
Dog d;
animalSound(c);  // 输出:猫咪在喵喵叫
animalSound(d);  // 输出:小狗在汪汪叫

五、其他关键知识点

  1. 静态成员(static)
  • 特性:属于类本身,所有对象共享,生命周期与程序一致(不依赖对象)。
  • 实操示例:
class Counter {
public:
    static int count;  // 静态成员变量(类内声明,类外初始化)
    static void addCount() {  // 静态成员函数(无this指针,只能访问静态成员)
        count++;
    }
};

// 静态成员变量类外初始化(必须写,否则编译错误)
int Counter::count = 0;

// 调用示例(无需创建对象,直接通过类名访问)
Counter::addCount();
cout << Counter::count << endl;  // 输出:1
  1. 友元(friend)
  • 核心作用:让外部函数/类访问当前类的 private / protected 成员(打破封装,谨慎使用)。
  • 3种形式:
class Car {
private:
    int speed;
    // 1. 友元函数(外部函数可访问类内成员)
    friend void showSpeed(Car& c);
    // 2. 友元类(整个类的函数都可访问)
    friend class Mechanic;
public:
    Car(int s) : speed(s) {}
};

// 友元函数实现
void showSpeed(Car& c) {
    cout << "车速:" << c.speed << endl;  // 可访问private成员
}

// 友元类
class Mechanic {
public:
    void modifySpeed(Car& c, int s) {
        c.speed = s;  // 可访问private成员
    }
};
 
  1. 常成员(const)
  • 常成员变量:初始化后不可修改,必须通过构造函数初始化列表赋值。
  • 常成员函数:不可修改类的成员变量( mutable 变量除外),声明时在函数末尾加 const 。
class Person {
private:
    const string id;  // 常成员变量(不可修改)
    string name;
    mutable int count;  // 可在常函数中修改
public:
    // 初始化列表(必须用于常成员变量初始化)
    Person(string i, string n) : id(i), name(n), count(0) {}
    // 常成员函数(末尾加const)
    void showInfo() const {
        cout << "ID:" << id << ",姓名:" << name << endl;
        count++;  // mutable变量可修改
        // name = "张三";  // 错误:常函数不可修改普通成员变量
    }
};
 

六、核心易错点

  1. 构造函数无返回值,不可写 void ;
  2. 堆上创建的对象( new )必须手动 delete ,否则内存泄漏;
  3. 拷贝构造函数的参数必须是“常量引用”( const 类名& ),避免无限递归;
  4. 多态的实现必须满足“虚函数+重写+父类指针/引用”,缺一不可;
  5. 静态成员变量必须在类外初始化,否则编译报错。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐