C++继承

本文涉及的产品
访问控制,不限时长
简介: C++继承

一、继承


1、概念:通过一种机制表达类型之间共性和特性的方式,利用已有的数据类型来定义新的数据类型,这种机制就是继承.


2、语法:


class 子类:继承方式1 基类1,继承方式2 基类2,...{

       ...


   };


   继承方式:


   -->public(公有继承)


   -->protected(保护继承)


   -->private(私有继承)


#include <iostream>
using namespace std;
//人类(基类)
class Human{
public:
    Human(const string& name,int age)
        :m_name(name),m_age(age){}
    void eat(const string& food){
        cout << "我在吃" << food << endl;
    }
    void sleep(int hour){
        cout << "我睡了" << hour << "小时"
            << endl;
    }
protected://保护成员可以在类的内部和子类中访问
    string m_name;
    int m_age;
};
//学生类(人类派生的一个子类)
class Student:public Human{
public:
    //Human(...):指明基类部分的初始化方式
    Student(const string& name,int age,int no)
        :Human(name,age),m_no(no){}
    void learn(const string& course){
        cout << "我在学" << course << endl;
    }
    void who(void){
        cout << "我叫" << m_name << ",今年" <<
            m_age << "岁,学号是" << m_no <<
            endl;
    }
private:
    int m_no;
};
//教师类(人类派生的另一个子类)
class Teacher:public Human{
public:
    Teacher(const string& name,int age,
        int salary):Human(name,age),
                    m_salary(salary){}
    void teach(const string& course){
        cout << "我在讲" << course << endl;
    }
    void who(void)const{
        cout << "我叫" << m_name << ",今年" <<
            m_age << "岁,工资是" << m_salary
            << endl;
    }
private:
    int m_salary;
};
int main(void)
{
    Student s("关羽",30,10011);
    s.who();
    s.eat("牛肉拉面");
    s.sleep(8);
    s.learn("孙武兵法");
   
    Teacher t("孙悟空",35,80000);
    t.who();
    t.eat("桃子");
    t.sleep(6);
    t.teach("unix系统编程");
    //Student*-->Human*:向上造型
    Human* ph = &s;
    ph->eat("兰州拉面");
    ph->sleep(7);
    //ph->who();//error
    //Human*-->Student*:向下造型(合理)
    Student* ps = static_cast<Student*>(ph);
    ps->who();
    Human h("林黛玉",22);
    //Human*-->Student*:向下造型(不合理)
    Student* ps2 = static_cast<Student*>(&h);
    ps2->who();//危险
    //int * pi = new int(100);
    //Student* ps3 = (Student*)pi;
    //ps3->who();
 
    return 0;
}
运行结果:
我叫关羽,今年30岁,学号是10011
我在吃牛肉拉面
我睡了8小时
我在学孙武兵法
我叫孙悟空,今年35岁,工资是80000
我在吃桃子
我睡了6小时
我在讲unix系统编程
我在吃兰州拉面
我睡了7小时
我叫关羽,今年30岁,学号是10011
我叫林黛玉,今年22岁,学号是-858993460


3、子类继承基类的成员:公有、保护、私有


通过子类,可以直接访问基类中的公有成员和保护成员,就如同它们被声明在子类中一样,但基类中的私有成员,受到访问控制属性的影响,继承后不能直接访问,但是可以让基类提供公有或保护的接口函数来间接访问.


注:基类构造函数和析构函数子类无法继承。


#include <iostream>
using namespace std;
class Base {//基类
public:
    void public_func(void) {
        cout << "基类的公有成员" << endl;
    }
protected:
    void protected_func(void) {
        cout << "基类的保护成员" << endl;
    }
public:
    void getPrivate(void) {
        private_func();
    }
private:
    void private_func(void) {
        cout << "基类的私有成员" << endl;
    }
};
class Derived :public Base {//子类
public:
    void func(void) {
        public_func();
        protected_func();
        //private_func();//error
        getPrivate();
    }
};
int main(void)
{
    Derived d;
    d.func();
}
运行结果:
基类的公有成员
基类的保护成员
基类的私有成员


4、子类隐藏基类的成员


如果子类和基类中定义了同名的成员函数,因为作用域不同,不能构成重载关系,而是一种隐藏关系,当通过子类访问该成员时,将优先访问子类自己的成员。如果需要通过子类访问基类中被隐藏的成员,可以显式的通过"类名::"来指明。


如果形成隐藏关系的成员函数满足不同参的重载条件,也可以通过using声明,将基类中成员函数引入子类作用域,让它们形成有效的重载关系,通过重载匹配来解决//不推荐


#include <iostream>
using namespace std;
class Base{
public:
    void func(int i){
        cout << "Base::func(int)" << endl;
    }
};
class Derived:public Base{
public:
    void func(void){
        cout << "Derived::func(void)" << endl;
    }
    //将基类中的func声明到当前子类作用域,让
    //它们构成函数重载关系
    //using Base::func;
};
int main(void)
{
    Derived d;
    d.Base::func(10);
    d.func();
    return 0;
}
运行结果:
Base::func(int)
Derived::func(void)

5、访问控制限定符:影响访问该类的成员的位置


访问控制      访问控制        内部    子类    外部    友元


限定符          属性              访问    访问    访问    访问


public          公有成员        ok        ok        ok        ok


protected    保护成员        ok        ok        no        ok


private         私有成员        ok        no        no        ok


#include <iostream>
using namespace std;
class A {//基类
public:
    int m_public;//公有成员
protected:
    int m_protected;//保护成员
private:
    int m_private;//私有成员
};
class B :public A {//公有继承的子类
    void func(void) {
        m_public = 123;
        m_protected = 123;
        //m_private = 123;
    }
};
class C :protected A {//保护继承的子类
    void func(void) {
        m_public = 123;
        m_protected = 123;
        //m_private = 123;
    }
};
class D :private A {//私有继承的子类
    void func(void) {
        m_public = 123;
        m_protected = 123;
        //m_private = 123;
    }
};
class X :public B {
    void foo(void) {
        m_public = 123;
        m_protected = 123;
        //m_private = 123;
    }
};
class Y :public C {
    void foo(void) {
        m_public = 123;
        m_protected = 123;
        //m_private = 123;
    }
};
class Z :public D {
    void foo(void) {
        //m_public = 123;
        //m_protected = 123;
        //m_private = 123;
    }
};
int main(void)
{
    B b;
    b.m_public = 123;//ok
    //b.m_protected = 123;
    //b.m_private = 123;
    C c;
    //c.m_public = 123;
    //c.m_protected = 123;
    //c.m_private = 123;
    D d;
    //d.m_public = 123;
    //d.m_protected = 123;
    //d.m_private = 123;
    return 0;
}

6、子类的构造函数


如果子类的构造函数没有显式指明基类子对象的初始化方式,那么编译器将会自动调用基类的无参构造函数来初始化基类子对象。


如果希望基类子对象以有参的方式被初始化,则必须使用初始化列表。


#include <iostream>
using namespace std;
class Member{
public:
    Member(void):m_j(0){
        cout << "Member(void)" << endl;
    }
    Member(int j):m_j(j){
        cout << "Member(int)" << endl;
    }
    int m_j;
};
class Base{
public:
    Base(void):m_i(0){
        cout << "Base(void)" << endl;
    }
    Base(int i):m_i(i){
        cout << "Base(int)" << endl;
    }
    int m_i;
};
class Derived:public Base{
public:
    Derived(void){
        cout << "Derived(void)" << endl;
    }
    //Base(i):指明基类子对象的初始化方式
    //m_mem(i):指明成员子对象的初始化方式
    Derived(int i):Base(i),m_mem(i){
        cout << "Derived(int)" << endl;
    }
    Member m_mem;//成员子对象
};
int main(void)
{
    Derived d;
    cout << d.m_i << endl;//0
    Derived d2(123);
    cout << d2.m_i << endl;//123
    return 0;
}


7、子类的析构函数


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


子类对象的销毁过程:执行子类析构函数的代码,析构成员子对象(按声明逆序),析构基类子对象(按继承表逆序),释放内存


基类的析构函数不能自动调用子类的析构函数,所以对一个指向子类对象的基类指针使用delete操作符,实际被调用的仅是基类的析构函数,子类的析构函数执行不到,有内存泄漏的风险。


#include <iostream>
using namespace std;
class Member{
public:
    Member(void):m_j(0){
        cout << "Member(void)" << endl;
    }
    Member(int j):m_j(j){
        cout << "Member(int)" << endl;
    }
    ~Member(void){
        cout << "~Member(void)" << endl;
    }
    int m_j;
};
class Base{
public:
    Base(void):m_i(0){
        cout << "Base(void)" << endl;
    }
    Base(int i):m_i(i){
        cout << "Base(int)" << endl;
    }
    ~Base(void){
        cout << "~Base(void)" << endl;
    }
    int m_i;
};
class Derived:public Base{
public:
    Derived(void){
        cout << "Derived(void)" << endl;
    }
    //Base(i):指明基类子对象的初始化方式
    //m_mem(i):指明成员子对象的初始化方式
    Derived(int i):Base(i),m_mem(i){
        cout << "Derived(int)" << endl;
    }
    ~Derived(void){
        cout << "~Derived(void)" << endl;
    }
    Member m_mem;//成员子对象
};
int main(void)
{
    /* Derived d;
    cout << d.m_i << endl;//0
    Derived d2(123);
    cout << d2.m_i << endl;//123
    */
   
    Base* pb = new Derived;
    //...
    //pb->析构函数
    delete pb;//内存泄露问题
    return 0;
}
运行结果:
Base(void)
Member(void)
Derived(void)
~Base(void)
相关实践学习
消息队列+Serverless+Tablestore:实现高弹性的电商订单系统
基于消息队列以及函数计算,快速部署一个高弹性的商品订单系统,能够应对抢购场景下的高并发情况。
云安全基础课 - 访问控制概述
课程大纲 课程目标和内容介绍视频时长 访问控制概述视频时长 身份标识和认证技术视频时长 授权机制视频时长 访问控制的常见攻击视频时长
目录
相关文章
|
1月前
|
编译器 C++ 开发者
【C++】继承
C++中的继承是面向对象编程的核心特性之一,允许派生类继承基类的属性和方法,实现代码复用和类的层次结构。继承有三种类型:公有、私有和受保护继承,每种类型决定了派生类如何访问基类成员。此外,继承还涉及构造函数、析构函数、拷贝构造函数和赋值运算符的调用规则,以及解决多继承带来的二义性和数据冗余问题的虚拟继承。在设计类时,应谨慎选择继承和组合,以降低耦合度并提高代码的可维护性。
33 1
【C++】继承
|
5月前
|
编译器 C++
【C++】详解C++的继承
【C++】详解C++的继承
|
2月前
|
安全 程序员 编译器
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
91 11
|
2月前
|
C++
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
67 1
|
2月前
|
C++
C++番外篇——虚拟继承解决数据冗余和二义性的原理
C++番外篇——虚拟继承解决数据冗余和二义性的原理
48 1
|
2月前
|
安全 编译器 程序员
C++的忠实粉丝-继承的热情(1)
C++的忠实粉丝-继承的热情(1)
21 0
|
2月前
|
编译器 C++
C++入门11——详解C++继承(菱形继承与虚拟继承)-2
C++入门11——详解C++继承(菱形继承与虚拟继承)-2
41 0
|
2月前
|
程序员 C++
C++入门11——详解C++继承(菱形继承与虚拟继承)-1
C++入门11——详解C++继承(菱形继承与虚拟继承)-1
44 0
|
3月前
|
C++
C++(二十)继承
本文介绍了C++中的继承特性,包括公有、保护和私有继承,并解释了虚继承的作用。通过示例展示了派生类如何从基类继承属性和方法,并保持自身的独特性。此外,还详细说明了派生类构造函数的语法格式及构造顺序,提供了具体的代码示例帮助理解。
|
3月前
|
C++
c++继承层次结构实践
这篇文章通过多个示例代码,讲解了C++中继承层次结构的实践应用,包括多态、抽象类引用、基类调用派生类函数,以及基类指针引用派生类对象的情况,并提供了相关的参考链接。