{C++系列} C++基础 day09 继承,继承方式和访问控制属性,多重继承,钻石继承,虚继承
in C/C++ with 0 comment

{C++系列} C++基础 day09 继承,继承方式和访问控制属性,多重继承,钻石继承,虚继承

in C/C++ with 0 comment

#复习:

1 操作符重载

2# 继承

1)概念
基类派生子类,子类继承基类
2)语法

class 子类:继承方式 基类{...};
继承方式:public protected private

3公有继承特性

========================

二十一# 继承(Inheritance)

3# 公有继承的特性(public)

1) 子类对象可以当做基类对象来使用

注:子类对象中包含基类的部分称为“基类子对象”

#举例

公有继承举例

#include <iostream>
using namespace std;

class A{
public:
    void foo(void){
        cout << "A::foo(void)" << endl;
    }
};
class B:public A{
public:
    void foo(int i){
        cout << "B::foo(int)" << endl;
    }
    //将A中foo引入当前B的作用域,
    //可以和B中foo构成重载关系
    //using A::foo;
};
int main(void)
{
    B b;
    //通过作用域限定,说明要访问成员是A类中的
    b.A::foo();
    b.foo(100);
    return 0;
}

2)向上造型(重点掌握)

将子类类型指针或引用转换为基类类型的指针或引用。
这种操作性缩小的类型转换,在编译器看来是安全的,可以隐式完成转换。

    class A{};//基类
    class B:public A{};//子类
    B b;
    A* pa = &b;//向上造型
    A& ra = b;//向上造型
    ----------
    void func(A* pa){...}
    func(&b);//向上造型
    -----------
    void func(A& ra){...}
    func(b);//向上造型

#举例

#include <iostream>
using namespace std;

class A{
public:
    int m_public;
protected:
    int m_protected;
private:
    int m_private;
};
class B:public A{
public:
    void func(void){
        m_public = 10;
        m_protected = 10;
        //m_private = 10;
    }
};
class C:protected A{
public:
    void func(void){
        m_public = 10;
        m_protected = 10;
        //m_private = 10;
    }
};
class D:private A{
public:
    void func(void){
        m_public = 10;
        m_protected = 10;
        //m_private = 10;
    }
};
int main(void)
{
    B b;
    b.m_public = 10;//ok
    //b.m_protected = 10;//error
    //b.m_private = 10;//error

    C c;
    //c.m_public = 10;//error
    //c.m_protected = 10;//error
    //c.m_private = 10;//erorr

    D d;
    //d.m_public = 10;
    //d.m_protected = 10;
    //d.m_private = 10;
}

3)#向下造型//了解

将基类类型指针或引用转换为子类类型的指针或 引用。
这种操作性放大的类型转换在编译器看来是危险的,不能隐式转换,只能显示转换。

#举例

#include <iostream>
using namespace std;

class Base{
public:
    Base(void):m_i(0){
        cout << "Base::Base()" << endl;
    }
    Base(int i):m_i(i){
        cout << "Base::Base(int)" << endl;
    }
    int m_i;
};
class Member{
public:
    Member(void):m_i(0){
        cout << "Member::Member()" << endl;
    }
    Member(int i):m_i(i){
        cout << "Member::Member(int)" << endl;
    }
    int m_i;
};
class Derived:public Base{
public:
    Derived(void){
        cout << "Derived::Derived()" << endl;
    }
    //Base(i):指明基类子对象用i做为构造实参来初始化
    //m_member(i):知名成员子对象用i来初始化
    Derived(int i):Base(i),m_member(i){
        cout << "Derived::Derived(int)" << endl;
    }
    Member m_member;
};
int main(void)
{
    Derived d;
    cout << d.m_i << ',' << d.m_member.m_i 
        << endl;//0
    Derived d2(123);
    cout << d2.m_i << ',' << d2.m_member.m_i
        << endl;//123
    return 0;
}

4)#子类继承基类的成员

class 子类:public 基类{
   子类(..):基类(实参){}
};

#举例

#include <iostream>
using namespace std;

class Base{
public:
    Base(void):m_i(0){}
    Base(int i):m_i(i){}
    Base(const Base& that):m_i(that.m_i){
        cout << "Base::Base(const Base&)" << endl;
    }
    Base& operator=(const Base& that){
        cout << "Base::operator=(...)" << endl;
        if(&that != this){
            m_i = that.m_i;
        }
        return *this;
    }
    int m_i;
};
class Derived:public Base{
public:
    Derived(void):m_i(0){}
    Derived(int i1,int i2):Base(i1),m_i(i2){}
    //Base(that):说明基类子对象以拷贝方式初始化
    Derived(const Derived& that)
        :m_i(that.m_i),Base(that){}
    Derived& operator=(const Derived& that){
        if(&that != this){
            m_i = that.m_i;
            //调用基类的拷贝赋值函数,完成基类
            //子对象的复制操作
            Base::operator=(that);
        }
        return *this;
    }
    int m_i;
};
int main(void)
{
    Derived d1(100,200);
    Derived d2(d1);//拷贝构造
    cout << d1.Base::m_i << ',' << d1.m_i << endl;
    cout << d2.Base::m_i << ',' << d2.m_i << endl;
    Derived d3;
    d3 = d1;//拷贝赋值,d3.operator=(d1);
    cout << d3.Base::m_i << ',' << d3.m_i << endl;
    
}

5)#子类隐藏基类的成员

#include <iostream>
using namespace std;

//电话类
class Phone{
public:
    Phone(const string& number):m_number(number){}
    void call(const string& number){
        cout << m_number << "打给" << 
            number << endl;
    }
private:
    string m_number;
};
//播放器
class Player{
public:
    Player(const string& media):m_media(media){}
    void play(const string& music){
        cout << m_media << "播放器播放" << 
            music << endl;
    }
private:
    string m_media;
};
//计算机类
class Computer{
public:
    Computer(const string& os):m_os(os){}
    void run(const string& app){
        cout << "在" << m_os << "系统上运行"
            << app << endl;
    }
private:
    string m_os;
};
//智能手机
class SmartPhone
    :public Phone,public Player,public Computer{
public:
    SmartPhone(const string& number,
        const string& media,const string& os)
            :Phone(number),Player(media),
                Computer(os){}
};
int main(void)
{
    SmartPhone iponeX("18688886666","MP5","Andorid");
    iponeX.call("010-62132018");
    iponeX.play("最炫小苹果.mp3");
    iponeX.run("王者荣耀");
    SmartPhone* p1 = &iponeX;
    Phone* p2 = p1;
    Player* p3 = p1;
    Computer* p4 = p1;
    cout << "p1=" << p1 << endl;
    cout << "p2=" << p2 << endl;
    cout << "p3=" << p3 << endl;
    cout << "p4=" << p4 << endl;
    return 0;
}

4 继承方式和访问控制属性

1)#三种访问控制属性:影响访问该类成员的位置

访问控制       访问控制    内部    子类    外部    友元
限定符        属性        访问    访问    访问    访问
public        公有成员    ok     ok     ok     ok
protected    保护成员    ok     ok    no     ok
private        私有成员 ok     no    no     ok

===============================

#举例

#include <iostream>
using namespace std;

class A{
public:
    void foo(void){
        cout << "A::foo(void)" << endl;
    }
};
class B{
public:
    void foo(int i){
        cout << "B::foo(int)" << endl;
    }
};
class C:public A,public B{
public:
//    using A::foo;
//    using B::foo;
};
int main(void)
{
    C c;
    c.A::foo();
    c.B::foo(123);
    return 0;
}

2)#三种基类继承方式:影响通过子类访问基类中的成员的可访问性

基类中的        在公有子    在保护子    在私有子
               类中变成    类中变成   类中变成
公有成员        公有成员    保护成员    私有成员
保护成员        保护成员    保护成员    私有成员
私有成员        私有成员    私有成员    私有成员

#举例

#include <iostream>
using namespace std;

class A{
public:
    A(int data):m_data(data){
        cout << "A::" << this << "," << 
            sizeof(A) << endl;
    }
protected:
    int m_data;
};
class B:virtual public A{//虚继承
public:
    B(int data):A(data){
        cout << "B::" << this << "," << 
            sizeof(B) << endl;
    }
    void set(int data){
        m_data = data;
    }
};
class C:virtual public A{
public:
    C(int data):A(data){
        cout << "C::" << this << "," << 
            sizeof(C) << endl;
    }
    int get(void){
        return m_data;
    }
};
class D:public B,public C{
public:
    //虚继承时,由末端的汇聚子类负责构造
    //公共基类子对象
    D(int data):B(data),C(data),A(data){
        cout << "D::" << this << "," << 
            sizeof(D) << endl;
    }
};
int main(void)
{
    D d(100);
    cout << d.get() << endl;//100
    d.set(200);
    cout << d.get() << endl;//?200?
}

5# 子类的构造函数

6# 子类的析构函数

1)子类析构函数在执行后,会自动调用基类的析构函数,析构基类子对象。
2)对象的销毁过程

3)基类析构函数不会调用子类的析构函数,所以对一个指向子类对象的基类指针delete运算符,实际被执行的将只是基类的析构函数,而子类的析构函数不会被执行,有内存泄露的风险。

   class A{...};
   class B:public A{...};
   A* pa = new B;//pa是一个指向子类对象的基类指针
   delete pa;//只调用A的析构,有内存泄露风险

7# 子类的拷贝构造和拷贝赋值

1)#拷贝构造

2)#拷贝赋值

8# 多重继承

1)#一个子类同时继承多个基类,这样的继承方式称为多重继承。

电话  播放器  计算机
  \     |    /
    智能手机

2)向上造型时,编译器会根据各个基类子对象,在子类对象中的内存布局,进行适当的偏移计算,保证指针的类型与其所指向的目标对象类型一致。

3)#名字冲突问题

9# 钻石继承

1)#一个子类的多个基类源自共同的"祖先"基类,这样的继承结果称为钻石继承
2#公共基类(A)子对象在汇聚子类(D)对象中存在多个实例,在通过汇聚子类对象去访问公共基类中的成员,会因为继承路径不同导致不一致。

   A
  / \
 B   C
  \ /
   D 

3)#通过虚继承可以让共基类子(A)对象实例唯一,并且为所有的子类共享,这样即使沿着不同路径去访问公共基类中的成员一定是一致的。

10# 虚继承语法

1)继承表中使用virtual关键字修饰

2)位于继承链最末端的子类负责构造公共基类子对象

注:虚继承时,公共基类(A)的所有子类都要在初始化表中指明其初始化方式,否则编译器将会以无参方式进行初始化。

Responses