1. 继承
class 子类名 : 继承方式1 基类1,继承方式2 基类2,. . . { }
继承方式:
public 公有继承(最常用方式) “是”关系
private 私有继承(默认缺省方式) “拥有”关系
protected 保护继承(看作特殊的私有继承)
基类 派生 子类
子类 继承 基类
2. 公有继承
class Human {
public:
Human(const string& name = "", int age = 0) : m_name(name), m_age(age) {}
// 这里要给参数设置缺省值,可以不用写缺省构造函数,如果没有,则编译器报错;
void who() const {
cout << m_name << m_age << endl;
}
void eat(const string& food) const { cout << food << endl; // 吃饭动作,有参
protected: // 可以让子类使用,如果是 private 子类就无法调用
string m_name;
int m_age;
};
class Student : public Human {
public:
Student(const string& name, int age, int no) : m_no(no) { // m_no 可以在初始化列表初始化
m_name = name; // m_name 是继承来的,不能在初始化列表里面这样写:m_name(name);
m_age = age;
}
/*
也可以这样给 m_name 和 m_age 初始化:
Student(const string& name, int age, int no) : Human(name, age), m_no(no) {}
如果这样初始化,那么上面基类里的 Human 就不用设置参数缺省值;
*/
void learn(const string& lesson) const { // 学习动作
cout << lesson << endl;
}
private:
int m_no; // 学号属性
}
int main() {
Student s1("zhangfei", 25, 111); // 在调用 Student 构造函数的时候,也在调用 Human() 的无参构造函数
s1.who(); // s1 可以直接调用基类的 who 成员函数
s1.eat("kfc");
s1.learn();
return 0;
}
这里 m_name 和 m_age 称作子类对象中的基类子对象;
主函数里构造学生对象 s1 的时候,就要初始化 m_name 和 m_age,方法有三:
a. 定义 Human 默认构造函数;
b. 给 Human 参数表定义默认值;
c. 在学生类构造函数初始化类表里面给 m_name 和 m_age 初始化;
3. 通过继承,在基类中定义的任何成员,也都成了子类的成员;
但是基类的私有成员,子类虽然拥有,却不能直接访问;
子类可以通过基类的成员函数间接访问私有成员;
基类中的保护成员可以被子类直接访问;但不能在其他类和全局中被访问;
任何一个子类对象中都包含着基类子对象;
一个子类对象在任何时候都可以被视为基类对象;
也就是说,任何时候一个子类对象的指针和引用,都可以被隐式转换为基类类型的指针或引用;
反之不行,不过可以显式转换;
Student s1(...);
Human* h = &s1; // ok
h -> who(); // ok
h -> learn(); // error
Student *sp;
sp = h; // error,隐式转换;
sp = static_cast<Student*> (h); // ok,显式转换;
这里 h 虽然指向 s1,但是不能访问 Student 的成员函数;
h 的访问范围由它的类型 Human 决定;
Human 访问范围小于 Student,Student 转为 Human 是往小里转,安全,所以计算机可以隐式转换;
而反过来则不安全,必须显式转换;
&n
class 子类名 : 继承方式1 基类1,继承方式2 基类2,. . . { }
继承方式:
public 公有继承(最常用方式) “是”关系
private 私有继承(默认缺省方式) “拥有”关系
protected 保护继承(看作特殊的私有继承)
基类 派生 子类
子类 继承 基类
2. 公有继承
class Human {
public:
Human(const string& name = "", int age = 0) : m_name(name), m_age(age) {}
// 这里要给参数设置缺省值,可以不用写缺省构造函数,如果没有,则编译器报错;
void who() const {
cout << m_name << m_age << endl;
}
void eat(const string& food) const { cout << food << endl; // 吃饭动作,有参
protected: // 可以让子类使用,如果是 private 子类就无法调用
string m_name;
int m_age;
};
class Student : public Human {
public:
Student(const string& name, int age, int no) : m_no(no) { // m_no 可以在初始化列表初始化
m_name = name; // m_name 是继承来的,不能在初始化列表里面这样写:m_name(name);
m_age = age;
}
/*
也可以这样给 m_name 和 m_age 初始化:
Student(const string& name, int age, int no) : Human(name, age), m_no(no) {}
如果这样初始化,那么上面基类里的 Human 就不用设置参数缺省值;
*/
void learn(const string& lesson) const { // 学习动作
cout << lesson << endl;
}
private:
int m_no; // 学号属性
}
int main() {
Student s1("zhangfei", 25, 111); // 在调用 Student 构造函数的时候,也在调用 Human() 的无参构造函数
s1.who(); // s1 可以直接调用基类的 who 成员函数
s1.eat("kfc");
s1.learn();
return 0;
}
这里 m_name 和 m_age 称作子类对象中的基类子对象;
主函数里构造学生对象 s1 的时候,就要初始化 m_name 和 m_age,方法有三:
a. 定义 Human 默认构造函数;
b. 给 Human 参数表定义默认值;
c. 在学生类构造函数初始化类表里面给 m_name 和 m_age 初始化;
3. 通过继承,在基类中定义的任何成员,也都成了子类的成员;
但是基类的私有成员,子类虽然拥有,却不能直接访问;
子类可以通过基类的成员函数间接访问私有成员;
基类中的保护成员可以被子类直接访问;但不能在其他类和全局中被访问;
任何一个子类对象中都包含着基类子对象;
一个子类对象在任何时候都可以被视为基类对象;
也就是说,任何时候一个子类对象的指针和引用,都可以被隐式转换为基类类型的指针或引用;
反之不行,不过可以显式转换;
Student s1(...);
Human* h = &s1; // ok
h -> who(); // ok
h -> learn(); // error
Student *sp;
sp = h; // error,隐式转换;
sp = static_cast<Student*> (h); // ok,显式转换;
这里 h 虽然指向 s1,但是不能访问 Student 的成员函数;
h 的访问范围由它的类型 Human 决定;
Human 访问范围小于 Student,Student 转为 Human 是往小里转,安全,所以计算机可以隐式转换;
而反过来则不安全,必须显式转换;
&n