面向对象速成

一、class 就是带权限控制的 struct

  • struct 默认内容权限为 public(公有),谁都能用
  • class 默认内容权限为 private(私有),只有自己能用,其他人只能用 public 的内容
class Animal
{
private: // 私有,藏起来的信息
    int age;

public: // 公有,大家能用的信息
    void setAge(int a)
    {
        age = a;
    }
    int getAge()
    {
        return age;
    }
};
Animal a;
a.setAge(3);
cout << a.getAge() << "\n"; // 输出 3
// cout << a.age << "\n"; // 编译错误

二、继承

class Animal
{
public:
    string name;
    void eat()
    {
        cout << name << "吃饭\n";
    }
};

class Cat : public Animal
{
public:
    void say()
    {
        cout << name << "喵\n";
    }
};

Cat d;
d.name = "咪咪";
d.eat(); // 输出:咪咪吃饭
d.say(); // 输出:咪咪喵
  • 默认继承(private 继承):父类的 public 和 protected 成员在子类里变成 private,子类内部能用,但外面不能通过子类对象用。父类的 private 成员子类不能用。
  • public 继承:父类的 public 和 protected 子类可以用,父类的 private 子类不能用。

多态与虚函数

class Animal
{
public:
    string name;
    virtual void say()
    {
        cout << name << "...\n";
    }
    virtual ~Animal()
};

class Dog : public Animal
{
public:
    void say() override
    {
        cout << name << "汪\n";
    }
};

class Cat : public Animal
{
public:
    void say() override
    {
        cout << name << "喵\n";
    }
};

Animal *p1 = new Dog();
Animal *p2 = new Cat();
p1->name = "小黑";
p2->name = "咪咪";
p1->say(); // 小黑汪
p2->say(); // 咪咪喵
delete p1;
delete p2;
  • 用父类指针或引用才能多态。
  • 用父类对象赋值会切片,子类独有部分丢掉,也不会多态。

构造函数与析构函数

  • 构造函数:创造的时候调用
  • 析构函数:删除的时候调用
class 父类 {
public:
    父类() { ... }                  // 默认构造
    父类(参数) { ... }              // 带参构造
    virtual ~父类() { ... }         // 虚析构
};
class 子类 : public 父类 {
public:
    子类() : 父类() { ... }         // 先调父类默认构造,可以不写 父类(),会自动调用
    子类(参数) : 父类(参数) { ... }  // 先调父类带参构造
    ~子类() { ... }                 // 先子后父
};

例子

class Animal
{
public:
    string name;
    int age;

    // 默认构造
    Animal()
    {
        name = "无名";
        age = 0;
        cout << "Animal 默认构造\n";
    }

    // 带参构造
    Animal(string n, int a)
    {
        name = n;
        age = a;
        cout << "Animal 带参构造 " << name << "\n";
    }

    // 虚析构
    virtual ~Animal()
    {
        cout << "Animal 析构 " << name << "\n";
    }
};
class Dog : public Animal
{
public:
    // 子类默认构造:自动先调 Animal()
    Dog()
    {
        cout << "Dog 默认构造\n";
    }

    // 子类带参构造:用初始化列表调 Animal(n, a)
    Dog(string n, int a) : Animal(n, a)
    {
        cout << "Dog 带参构造 " << name << "\n";
    }

    // 子类析构:先执行这里,再执行 Animal::~Animal()
    ~Dog()
    {
        cout << "Dog 析构 " << name << "\n";
    }
};
cout << "--- 造 d1 ---\n";
Dog d1;
cout << "--- 造 d2 ---\n";
Dog d2("小黑", 3);
cout << "--- new 一只狗,用父类指针 ---\n";
Animal *p = new Dog("小花", 2);
cout << "--- delete ---\n";
delete p;
cout << "--- 程序结束,自动销毁 d2、d1 ---";
  • 父类如果没写构造函数,编译器会偷偷生成父类的默认构造。
  • 父类如果写了带参构造,那就没有默认构造了,子类必须写先调父类的带参构造。
分类: 分享 · 更新时间 2026-9-12 8:20:37