C++继承

格式:

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;
}

解决方法:虚析构函数 

原文地址:https://www.cnblogs.com/liming19680104/p/13573994.html