Skip to content

C++ 继承

继承是面向对象编程的一个重要特性,它允许一个类(派生类)继承另一个类(基类)的属性和方法。

1. 继承的基本概念

1.1 基本语法

cpp
class 派生类名 : 访问修饰符 基类名 {
    // 派生类的成员
};

示例

cpp
#include <iostream>

class Animal {
public:
    void eat() {
        std::cout << "动物吃东西" << std::endl;
    }
    
    void sleep() {
        std::cout << "动物睡觉" << std::endl;
    }
};

class Dog : public Animal {
public:
    void bark() {
        std::cout << "狗叫" << std::endl;
    }
};

int main() {
    Dog dog;
    dog.eat();
    dog.sleep();
    dog.bark();
    
    return 0;
}

2. 访问修饰符和继承

2.1 public 继承

public继承中,基类的public成员在派生类中仍然是publicprotected成员在派生类中仍然是protectedprivate成员在派生类中不可访问。

cpp
#include <iostream>

class Base {
public:
    int public_var;
    
protected:
    int protected_var;
    
private:
    int private_var;
};

class Derived : public Base {
public:
    void access_members() {
        public_var = 10;
        protected_var = 20;
        // private_var = 30;  // 错误:不能访问 private 成员
    }
};

int main() {
    Derived derived;
    derived.public_var = 10;
    // derived.protected_var = 20;  // 错误:不能访问 protected 成员
    // derived.private_var = 30;  // 错误:不能访问 private 成员
    
    return 0;
}

2.2 protected 继承

protected继承中,基类的publicprotected成员在派生类中都变成protectedprivate成员在派生类中不可访问。

cpp
#include <iostream>

class Base {
public:
    int public_var;
    
protected:
    int protected_var;
    
private:
    int private_var;
};

class Derived : protected Base {
public:
    void access_members() {
        public_var = 10;
        protected_var = 20;
        // private_var = 30;  // 错误:不能访问 private 成员
    }
};

int main() {
    Derived derived;
    // derived.public_var = 10;  // 错误:不能访问 protected 成员
    // derived.protected_var = 20;  // 错误:不能访问 protected 成员
    // derived.private_var = 30;  // 错误:不能访问 private 成员
    
    return 0;
}

2.3 private 继承

private继承中,基类的publicprotected成员在派生类中都变成privateprivate成员在派生类中不可访问。

cpp
#include <iostream>

class Base {
public:
    int public_var;
    
protected:
    int protected_var;
    
private:
    int private_var;
};

class Derived : private Base {
public:
    void access_members() {
        public_var = 10;
        protected_var = 20;
        // private_var = 30;  // 错误:不能访问 private 成员
    }
};

int main() {
    Derived derived;
    // derived.public_var = 10;  // 错误:不能访问 private 成员
    // derived.protected_var = 20;  // 错误:不能访问 private 成员
    // derived.private_var = 30;  // 错误:不能访问 private 成员
    
    return 0;
}

3. 继承的类型

3.1 单继承

单继承是指一个派生类只继承一个基类。

cpp
#include <iostream>

class Animal {
public:
    void eat() {
        std::cout << "动物吃东西" << std::endl;
    }
};

class Dog : public Animal {
public:
    void bark() {
        std::cout << "狗叫" << std::endl;
    }
};

int main() {
    Dog dog;
    dog.eat();
    dog.bark();
    
    return 0;
}

3.2 多继承

多继承是指一个派生类继承多个基类。

cpp
#include <iostream>

class Animal {
public:
    void eat() {
        std::cout << "动物吃东西" << std::endl;
    }
};

class Pet {
public:
    void play() {
        std::cout << "宠物玩耍" << std::endl;
    }
};

class Dog : public Animal, public Pet {
public:
    void bark() {
        std::cout << "狗叫" << std::endl;
    }
};

int main() {
    Dog dog;
    dog.eat();
    dog.play();
    dog.bark();
    
    return 0;
}

3.3 多层继承

多层继承是指派生类继承自另一个派生类。

cpp
#include <iostream>

class Animal {
public:
    void eat() {
        std::cout << "动物吃东西" << std::endl;
    }
};

class Mammal : public Animal {
public:
    void give_birth() {
        std::cout << "哺乳动物生宝宝" << std::endl;
    }
};

class Dog : public Mammal {
public:
    void bark() {
        std::cout << "狗叫" << std::endl;
    }
};

int main() {
    Dog dog;
    dog.eat();
    dog.give_birth();
    dog.bark();
    
    return 0;
}

4. 构造函数和析构函数的执行顺序

4.1 构造函数的执行顺序

构造函数的执行顺序是:先执行基类的构造函数,再执行派生类的构造函数。

cpp
#include <iostream>

class Base {
public:
    Base() {
        std::cout << "基类构造函数" << std::endl;
    }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "派生类构造函数" << std::endl;
    }
};

int main() {
    Derived derived;
    
    return 0;
}

4.2 析构函数的执行顺序

析构函数的执行顺序是:先执行派生类的析构函数,再执行基类的析构函数。

cpp
#include <iostream>

class Base {
public:
    ~Base() {
        std::cout << "基类析构函数" << std::endl;
    }
};

class Derived : public Base {
public:
    ~Derived() {
        std::cout << "派生类析构函数" << std::endl;
    }
};

int main() {
    Derived derived;
    
    return 0;
}

5. 方法重写

方法重写是指在派生类中重新定义基类的方法。

cpp
#include <iostream>

class Animal {
public:
    void make_sound() {
        std::cout << "动物发出声音" << std::endl;
    }
};

class Dog : public Animal {
public:
    void make_sound() {
        std::cout << "狗叫" << std::endl;
    }
};

class Cat : public Animal {
public:
    void make_sound() {
        std::cout << "猫叫" << std::endl;
    }
};

int main() {
    Animal animal;
    Dog dog;
    Cat cat;
    
    animal.make_sound();
    dog.make_sound();
    cat.make_sound();
    
    return 0;
}

6. 使用基类指针

6.1 基类指针指向派生类对象

cpp
#include <iostream>

class Animal {
public:
    void make_sound() {
        std::cout << "动物发出声音" << std::endl;
    }
};

class Dog : public Animal {
public:
    void make_sound() {
        std::cout << "狗叫" << std::endl;
    }
    
    void bark() {
        std::cout << "狗叫" << std::endl;
    }
};

int main() {
    Animal* animal = new Dog();
    animal->make_sound();
    // animal->bark();  // 错误:不能调用派生类特有的方法
    
    delete animal;
    
    return 0;
}

6.2 使用 dynamic_cast

cpp
#include <iostream>

class Animal {
public:
    virtual void make_sound() {
        std::cout << "动物发出声音" << std::endl;
    }
};

class Dog : public Animal {
public:
    void make_sound() override {
        std::cout << "狗叫" << std::endl;
    }
    
    void bark() {
        std::cout << "狗叫" << std::endl;
    }
};

int main() {
    Animal* animal = new Dog();
    animal->make_sound();
    
    Dog* dog = dynamic_cast<Dog*>(animal);
    if (dog != nullptr) {
        dog->bark();
    }
    
    delete animal;
    
    return 0;
}

7. 虚继承

虚继承用于解决多重继承中的菱形继承问题。

cpp
#include <iostream>

class Animal {
public:
    void eat() {
        std::cout << "动物吃东西" << std::endl;
    }
};

class Mammal : virtual public Animal {
public:
    void give_birth() {
        std::cout << "哺乳动物生宝宝" << std::endl;
    }
};

class Pet : virtual public Animal {
public:
    void play() {
        std::cout << "宠物玩耍" << std::endl;
    }
};

class Dog : public Mammal, public Pet {
public:
    void bark() {
        std::cout << "狗叫" << std::endl;
    }
};

int main() {
    Dog dog;
    dog.eat();
    dog.give_birth();
    dog.play();
    dog.bark();
    
    return 0;
}

8. 示例:综合运用

现在,让我们看一个综合运用各种继承特性的例子:

cpp
#include <iostream>
#include <string>

class Person {
protected:
    std::string name;
    int age;

public:
    Person(std::string name, int age) : name(name), age(age) {}
    
    void introduce() {
        std::cout << "我叫" << name << ",今年" << age << "岁" << std::endl;
    }
};

class Student : public Person {
private:
    std::string school;
    float gpa;

public:
    Student(std::string name, int age, std::string school, float gpa) 
        : Person(name, age), school(school), gpa(gpa) {}
    
    void study() {
        std::cout << name << "在学习" << std::endl;
    }
    
    void introduce() {
        Person::introduce();
        std::cout << "我在" << school << "上学,GPA是" << gpa << std::endl;
    }
};

class Teacher : public Person {
private:
    std::string subject;
    double salary;

public:
    Teacher(std::string name, int age, std::string subject, double salary) 
        : Person(name, age), subject(subject), salary(salary) {}
    
    void teach() {
        std::cout << name << "在教" << subject << std::endl;
    }
    
    void introduce() {
        Person::introduce();
        std::cout << "我教" << subject << ",工资是" << salary << std::endl;
    }
};

class TeachingAssistant : public Student, public Teacher {
public:
    TeachingAssistant(std::string name, int age, std::string school, float gpa, 
                      std::string subject, double salary)
        : Student(name, age, school, gpa), Teacher(name, age, subject, salary) {}
    
    void assist() {
        std::cout << "我在协助教学" << std::endl;
    }
};

int main() {
    Student student("张三", 20, "清华大学", 3.8f);
    std::cout << "学生:" << std::endl;
    student.introduce();
    student.study();
    std::cout << std::endl;
    
    Teacher teacher("李四", 35, "数学", 10000.0);
    std::cout << "老师:" << std::endl;
    teacher.introduce();
    teacher.teach();
    std::cout << std::endl;
    
    TeachingAssistant ta("王五", 25, "北京大学", 3.9f, "物理", 8000.0);
    std::cout << "助教:" << std::endl;
    ta.Student::introduce();
    ta.Teacher::introduce();
    ta.assist();
    
    return 0;
}

小结

C++ 继承包括:

  1. 继承的基本概念

    • 基本语法:class 派生类名 : 访问修饰符 基类名 { ... };
    • 派生类继承基类的属性和方法
  2. 访问修饰符和继承

    • public继承:基类的public成员在派生类中仍然是public
    • protected继承:基类的publicprotected成员在派生类中都变成protected
    • private继承:基类的publicprotected成员在派生类中都变成private
  3. 继承的类型

    • 单继承:一个派生类只继承一个基类
    • 多继承:一个派生类继承多个基类
    • 多层继承:派生类继承自另一个派生类
  4. 构造函数和析构函数的执行顺序

    • 构造函数:先执行基类的构造函数,再执行派生类的构造函数
    • 析构函数:先执行派生类的析构函数,再执行基类的析构函数
  5. 方法重写

    • 在派生类中重新定义基类的方法
  6. 使用基类指针

    • 基类指针可以指向派生类对象
    • 使用dynamic_cast进行类型转换
  7. 虚继承

    • 用于解决多重继承中的菱形继承问题

关键概念:

  • 继承:派生类继承基类的属性和方法
  • 单继承:一个派生类只继承一个基类
  • 多继承:一个派生类继承多个基类
  • 多层继承:派生类继承自另一个派生类
  • 方法重写:在派生类中重新定义基类的方法
  • 虚继承:用于解决多重继承中的菱形继承问题

掌握继承是 C++ 面向对象编程的重要基础,在后续章节中,我们将学习 C++ 的重载运算符和重载函数。