Appearance
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成员在派生类中仍然是public,protected成员在派生类中仍然是protected,private成员在派生类中不可访问。
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继承中,基类的public和protected成员在派生类中都变成protected,private成员在派生类中不可访问。
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继承中,基类的public和protected成员在派生类中都变成private,private成员在派生类中不可访问。
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++ 继承包括:
继承的基本概念:
- 基本语法:
class 派生类名 : 访问修饰符 基类名 { ... }; - 派生类继承基类的属性和方法
- 基本语法:
访问修饰符和继承:
public继承:基类的public成员在派生类中仍然是publicprotected继承:基类的public和protected成员在派生类中都变成protectedprivate继承:基类的public和protected成员在派生类中都变成private
继承的类型:
- 单继承:一个派生类只继承一个基类
- 多继承:一个派生类继承多个基类
- 多层继承:派生类继承自另一个派生类
构造函数和析构函数的执行顺序:
- 构造函数:先执行基类的构造函数,再执行派生类的构造函数
- 析构函数:先执行派生类的析构函数,再执行基类的析构函数
方法重写:
- 在派生类中重新定义基类的方法
使用基类指针:
- 基类指针可以指向派生类对象
- 使用
dynamic_cast进行类型转换
虚继承:
- 用于解决多重继承中的菱形继承问题
关键概念:
- 继承:派生类继承基类的属性和方法
- 单继承:一个派生类只继承一个基类
- 多继承:一个派生类继承多个基类
- 多层继承:派生类继承自另一个派生类
- 方法重写:在派生类中重新定义基类的方法
- 虚继承:用于解决多重继承中的菱形继承问题
掌握继承是 C++ 面向对象编程的重要基础,在后续章节中,我们将学习 C++ 的重载运算符和重载函数。