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

    解决方法:虚析构函数 

  • 相关阅读:
    关于VBA的Exit For到底是怎样跳出for循环的小例子
    关于VBA的Exit For到底是怎样跳出for循环的小例子
    C#-Task.Run 和 Task.Factory.StartNew 区别
    java数组使用 四 反转数组元素
    java数组使用 三 循环数组元素
    java数组使用 二 数组的三种初始化
    java数组使用 一
    java方法 使用 四 可变参数
    java方法 使用 三 求阶乘
    java方法 使用 二 查找最大值
  • 原文地址:https://www.cnblogs.com/liming19680104/p/13573994.html
Copyright © 2020-2023  润新知