C++继承_ios

格式:

class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…    {     <派生类类体>    };

继承方式:公有继承(public)

     保护继承(protected)

       私有继承(private) ----默认

公有单继承

#include<iostream>
#include<string>

class Human { //基类
public:
Human(const std::string& name,int age):m_name(name), m_age(age){}
void eat(const std::string& food) {
std::cout << "我在吃" << food << std::endl;
}
void sleep(int hour) {
std::cout << "我睡了" << hour << "小时" << std::endl;
}
protected://保护成员,在类的内部和子类中可以使用,在外部不能使用
std::string m_name;
int m_age;
};

class Student :public Human { //公有单继承
public:
Student (const std::string&name,int age,int no):Human(name,age),m_no(no){}//子类初始化函数
//需要的参数:包括基类和子类需要初始化的形参
//Human(name,age) 调用基类初始化函数
void who(void) {
std::cout << "我叫" << m_name << ",今年" << m_age << "岁,学号是" << m_no << std::endl;
}
void learn(const std::string& course) {
std::cout << "我在学" << course << std::endl;
}

private:
int m_no;//学号
};

class Teacher :public Human {
public:
Teacher(const std::string& name, int age, int salary) :Human(name, age), m_salary(salary) {}
void who(void) {
std::cout << "我叫" << m_name << ",今年" << m_age << "岁,工资是" << m_salary << std::endl;
}
void teach(const std::string& course) {
std::cout << "我在讲" << course << std::endl;
}
private:
int m_salary;//工资

};

int main()
{
Student s("关羽", 30, 10010);
s.who();
s.eat("牛肉拉面");
s.sleep(6);
s.learn("孙子兵法");

Teacher t("李明", 52, 8000);
t.who();
t.sleep(4);
t.eat("米饭");
t.teach("C++编程");

return 0;
}

向上造型和向下造型:

向上造型:将子类类型的指针或引用转换为基类的指针或引用 

向下造型:将基类类型的指针或引用转换为子类的指针或引用

#include<iostream>
#include<string>

class Human {
public:
Human(const std::string& name,int age):m_name(name), m_age(age){}
void eat(const std::string& food) {
std::cout << "我在吃" << food << std::endl;
}
void sleep(int hour) {
std::cout << "我睡了" << hour << "小时" << std::endl;
}
protected:
std::string m_name;
int m_age;
};

class Student :public Human {
public:
Student (const std::string&name,int age,int no):Human(name,age),m_no(no){}

void who(void) {
std::cout << "我叫" << m_name << ",今年" << m_age << "岁,学号是" << m_no << std::endl;
}
void learn(const std::string& course) {
std::cout << "我在学" << course << std::endl;
}
private:
int m_no;
};

int main()
{
Student s("关羽", 30, 10010);
Human* ph = &s; //Student*-->Human* 向上造型
//可访问域缩小了(只能访问基类的成员和成员函数了),这种隐式转换是安全的

//Human*-->Student* 向下造型
//Student* ps = ph; //放大了可访问域,隐式转换非法的
Student* ps = static_cast<Student*>(ph); //向下造型必须显示转换

Human h("张飞", 28);
Student* ps1 = static_cast<Student*> (&h);//不合理的转换
//原本基类中没有的成员变量的数据会混乱
ps1->who(); //学号的输出是乱的
return 0;
}

私有成员的继承

子类继承了基类的私有成员,但是不能直接访问。可以通过公有函数或保护函数进行访问 

子类隐藏基类的成员(成员搜索方式)

子类的成员与基类的成员完全同名,此时子类隐藏了基类的成员 

成员搜索方式:

先在子类中找,子类中有就不到基类中找了,如果子类中没有,就到基类中找 

#include<iostream>
#include<string>

class Base {
public:
void func(void) {
std::cout << "基类func" << std::endl;
}

};

class Derived :public Base {
public:
void func(void) {
std::cout << "子类func" << std::endl;
}
};

int main()
{
Derived d;
d.func(); //子类与基类同名成员,调用子类本身成员
d.Base::func(); //通过子类对象调用基类的同名成员,需要加上基类作用域

return 0;
}
#include<iostream>
#include<string>

class Base {
public:
void func(int i) {
std::cout << "基类func i=" << i << std::endl;
}
void func(int i, int j) {
std::cout << "基类func i+j=" << i+j << std::endl;
}

};

class Derived :public Base {
public:
void func(void) {
std::cout << "子类func" << std::endl;
}
using Base::func;//将基类的成员引入到子类作用域
//这样两个同名函数形成重载关系
};

int main()
{
Derived d;
d.func();
d.func(100);
d.func(100,200);

return 0;
}

继承方式的影响

基类中的成员

公有继承的子类

保护继承的子类

私有继承的子类

公有成员

公有成员

保护成员

私有成员

保护成员

保护成员

保护成员

私有成员

私有成员

私有成员

私有成员

私有成员

向上造型不适用的情况 

保护继承和私有继承不适用

#include<iostream>
#include<string>

class Base {
public:
void func() {
std::cout << "基类func" <<std::endl;
}

};

class Derived :private Base {

};

int main()
{
Derived d;
Base b = &d; //向上造型 报错
/*
错误原因:子类Derived是私有继承,子类中的成员都变成的私有;在向上造型时,扩大了成员的可访问范围
*/

return 0;
}

子类没有构造函数时注意事项 

#include<iostream>

class Base {
public:
Base(void):m_i(0) {
std::cout << "基类无参构造函数" <<std::endl;
}
Base(int i) :m_i(i) {
std::cout << "基类有参构造函数" << std::endl;
}
int m_i;
};

class Derived :public Base {

};

int main()
{
Derived d; //子类没有构造函数时,默认调用基类的无参构造函数来初始化基类子对象
std::cout << d.m_i << std::endl;

//Derived d1(100); 报错--默认只能调用基类的无参构造函数


return 0;
}

子类析构函数

子类析构函数,无论是自定义还是编译器缺省提供的,都会调用基类析构函数来完成基类子对象的销毁

销毁顺序:执行子类析构函数-->析构成员子对象(按声明的逆序)-->执行基类析构函数-->析构基类子对象(按继承表逆序)-->释放内存 

向上造型时

#include<iostream>

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

class Derived :public Base {
public:
~Derived(void) {
std::cout << "子类析构" << std::endl;
}
};

int main()
{
Base* d=new Derived;
delete d; //有内存泄漏的风险
//原因:只执行基类析构函数

return 0;
}

解决方法:虚析构函数