美文网首页
C++继承,静态成员,const成员

C++继承,静态成员,const成员

作者: lieon | 来源:发表于2020-11-05 18:13 被阅读0次

    继承

    继承的方式有三种

    • 公共继承
    • 保护继承
    • 私有继承
    访问权限 public protected private
    对本类 可见 可见 可见
    对子类 可见 可见 不可见
    对外部(调用方) 可见 不可见 不可见

    继承中的对象模型

    • 父类中所有的非静态成员属性都会被子类继承下去
    • 父类中私有成员属性是被编译器给隐藏了,因此访问不到,但确实被继承下去了
    struct Person {
    public:
        int m_A;
    protected:
        int m_age;
    private:
        int m_B;
    };
    
    struct Student: public Person {
        int m_no;
    };
    
    Student 对象占用16个字节
    

    继承中构造和析构的顺序

    • 构造顺序:先构造父类,再构造子类
    • 析构:先析构子类,再析构父类

    继承中访问同名的成员

    • 子类对象可以直接访问子类中同名成员
    • 子类对象加作用域可以访问父类同名成员
    • 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数

    多继承

    C++允许一个类可以有多个父类

    class Student {
    public:
        int m_score;
        
        void study() {
           cout << "Student::study" << endl;
        }
    };
    
    class Workder {
    public:
        int m_salary;
        
        void work() {
            cout << "Workder::work" << endl;
        }con
    };
    
    class Undergraduate: public Student, public Workder {
    public:
        int m_grade;
        
        void play() {
            cout << "Undergraduate::play" << endl;
        }
    };
    

    多继承体系下的构造函数调用

    class Undergraduate: public Student, public Workder {
    public:
        int m_grade;
        
        Undergraduate(int grade, int score, int salary): Student(score), Workder(salary) {
            m_grade = grade;
        }
    };
    
    
    
    ## 多继承-虚函数
    - 如果子类继承多个父类都有虚函数,那么子类对象就会产生对应的多张虚表
      - ![image.png](https://img.haomeiwen.com/i5456635/938814dd437afbe3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/400)
    
    ## 同名函数,同名成员变量
    
    ```C++
    
    
    class Student {
    public:
        int m_score;
        int m_age;
    };
    
    class Workder {
    public:
        int m_salary;
        int m_age;
    };
    
    class Undergraduate: public Student, public Workder {
    public:
        int m_grade;
        int m_age;
        Undergraduate(int grade, int score, int salary): Student(score), Workder(salary) {
            m_grade = grade;
        }
    };
    
    void test() {
        Undergraduate ug(10, 10, 1);
        ug.Student::eat();
        ug.Workder::eat();
        ug.eat();
        
        ug.Student::m_age = 29;
        ug.Workder::m_age = 29;
        ug.m_age = 29;
    }
    

    菱形继承

    • 菱形继承带来的问题
      • 最低下子类从基类继承的成员变量冗余,重复
      • 最低子类无法访问基类的成员,有二义性
      • image.png
        class Person {
            int m_age;
        };
    
        class Student: public Person {
        public:
            int m_score;
        };
    
        class Workder: public Person {
        public:
            int m_salary;
        };
    
        class Undergraduate: public Student, public Workder {
        public:
            int m_grade;
        };
    

    虚继承

    • 虚继承可以解决菱形继承问题
    • Person称为虚基类
    • Workder的虚表存储的内容有
      • 虚表指针与本类起始的偏移量(一般是0)
      • 虚基类第一个成员与本类起始的偏移量
    image.png
    class Student: virtual public Person {
    public:
        int m_score;
    };
    
    class Workder: virtual public Person {
    public:
        int m_salary;
    };
    
    class Undergraduate: public Student, public Workder {
    public:
        int m_grade;
    };
    
    image.png image.png
    class Sleep: virtual public Animal { };
    
    class Tuo: virtual public Animal { };
    
    class SleepTuo: public Sleep, public Tuo { };
    
    /*
     Sleep 和 Tuo中通过虚继承存储的是一个vbptr(虚基类指针),该指针分别指向一个Sleep和Tuo的一个虚表,该虚表存储的是SleepTuo中一个地址偏移量
     ,通过该偏移量和vbptr的起始地址,得到最终指向的地址
     Sleep的vbptr指向: 0(起始值)+ 8(偏移量)= 8
     Tuo的vbptr指向: 4(起始值)+ 4(偏移量) = 8
     
     */
    
    

    静态成员

    • static修饰的成员变量\函数
    • 可以通过对象(对象.静态成员),对象指针(对象指针->静态成员), 类访问(类名::静态成员)
    • 静态成员变量
      • 存储在数据段(全局区,类似于全局变量),整个程序运行过程中只有一份内存
      • 对比全局变量,它可以设定访问权限(public, protected, private),达到局部共享的目的
      • 必须初始化,必须在类外部初始化,初始化不能带static,如果类的声明和实现分离(在实现的.cpp中初始化)
    • 静态成员函数
      • 内部不能使用this指针(this指针只能用在非静态成员函数内部)
      • 不能是虚函数(虚函数只能是非静态成员函数)
      • 内部不能访问非静态成员变量\函数,只能访问静态成员变量\函数
      • 非静态成员函数内部可以访问静态成员变量\函数
      • 构造函数,析构函数不能是静态
      • 当声明和实现分离时,实现不能带static

    静态成员的访问方式

    • 通过类名访问
    Perosn::m_age = 30;
    
    • 通过对象访问
    Perosn p;
    p.m_age = 0;
    
    class Car {
        int m_price;
        static int ms_count;
    public:
        static int getCount() {
            return ms_count;
        }
        
        Car(int price = 0): m_price(price) {
            ms_count++;
        }
        
        ~Car() {
        }
    };
    

    静态成员经典应用 - 单例模式

    class Rocket {
    private:
       static Rocket* ms_instace;
       Rocket() { }
       Rocket(const Rocket &rocket) { };
       Rocket &operator=(const Rocket &rocket) { return *this; };
    
    public:
       static Rocket* shared() {
           // 严格要讲,这段代码需要考虑线程安全的问题
           if (ms_instace == nullptr) {
               ms_instace = new Rocket();
           }
           return ms_instace;
       }
    };
    
    Rocket* Rocket::ms_instace = nullptr;
    

    const成员

    • const成员: 被const修饰的成员变量,非静态成员函数
    • const成员变量
      • 必须初始化(类内部初始化),可以在声明的时候直接初始化赋值
      • 非static的const成员变量还可以在初始化列表中初始化
    • const成员函数(非静态)
      • const关键字写在参数列表后面,函数的声明和实现必须带const
      • 内部不能修改费static成员变量
      • 内部只能调用 const 成员函数、 static 成员函数
      • 非const成员函数可以调用const成员函数
    • const成员函数和非const成员函数构成重载
      • 非const对象(指针)优先调用非const成员函数
    • const对象只能调用const成员函数,static函数
    • this指针的本质是指针常量,指针的指向不可以修改的
    • 在成员函数后面添加const,修饰的是this指向,让指针指向的值不可以修改, 常函数内不可以修改成员属性
    • 要在常函数中修改成员变量,可以给这个成员变量加上mutable关键字
    class Car {
        const int mc_wheelsCount = 20;
    public:
        Car(): mc_wheelsCount(10) {};
        
        void run() const {
            std::cout << "run()" << std::cout;
        }
    };
    
    

    引用类型成员

    • 引用类型成员变量必须初始化(不考虑static情况)
      • 在声明的时候直接初始化
      • 通过初始化列表初始化
    class Car {
        int age;
        int m_price = age;
    
    public:
        Car(int &price): m_price(price) {};
    };
    

    相关文章

      网友评论

          本文标题:C++继承,静态成员,const成员

          本文链接:https://www.haomeiwen.com/subject/dzlovktx.html