31 类的继承

31 CPP类的继承

 

 

 

 

 

 

 

 

 上面第2点说明下,如果手工调用派生类的析构函数,也会调用基类的析构函数。

 

#include <iostream>

using namespace std;

//操作内存修改私有属性
class Person {
    int m_age;
    int m_score;
public:
    string m_name;

    Person(string name, int age) {
        m_name = name;
        m_age = age;
        m_score = 0;
    }

    void show() const {
        cout << m_name << " " << m_age << " " << m_score << endl;
    }
};

void test() {
    Person p("hello", 22);
    p.show();
    //直接操作内存来修改private属性 m_age
    *((int *) &p) = 108;
    p.show();
    //直接操作内存来修改private属性 m_score
    *((int *) &p + 1) = 100;
    p.show();
}

int main() {
    test();
    return 0;
}
hello 22 0
hello 108 0
hello 108 100

 

#include <iostream>

using namespace std;
class A
{
private:
    int m_b;

public:
    int m_a;
    A() : m_a(0), m_b(0)
    {
        cout << "调用了基类的默认构造函数A()." << endl;
    }
    A(int a, int b) : m_a(a), m_b(b)
    {
        cout << "调用了基类的构造函数A(int a,int b)" << endl;
    }
    A(const A &a) : m_a(a.m_a), m_b(a.m_b)
    {
        cout << "调用了基类的拷贝构造函数A(const A &a)" << endl;
    }
    ~A()
    {
        cout << "调用了基类的析构函数" << endl;
    }
    void showA()
    {
        cout << "m_a=" << m_a << "  m_b" << m_b << endl;
    }
};

class B : public A
{
public:
    int m_c;
    B() : m_c(0), A() //派生类的默认构造函数,指明用基类的默认构造函数(不指明也无所谓)
    {
        cout << "调用了派生类的默认构造函数" << endl;
    }
    B(int a, int b, int c) : m_c(c), A(a, b) //指明用基类的两个参数的构造函数
    {
        cout << "调用了B的构造函数B(int a, int b, int c)" << endl;
    }
    B(const A &a, int c) : A(a), m_c(c) //指明用基类的拷贝构造函数
    {
        cout << "调用了派生类的构造函数B(cosnt A &a,int c)" << endl;
    }
    //显示派生类 B的全部的成员
    void showB()
    {
        cout << "m_c=" << m_c << endl;
    }
};

void test()
{
    B b1; //调用基类磨人的构造函数
    b1.showA();
    b1.showB();

    B b2(1, 2, 3);
    b2.showA();
    b2.showB();
    A a(12, 22);
    B b3(a, 23);
    b3.showA();
    b3.showB();
}

int main()
{
    test();
    return 0;
}
调用了基类的默认构造函数A().
调用了派生类的默认构造函数
m_a=0  m_b0
m_c=0
调用了基类的构造函数A(int a,int b)
调用了B的构造函数B(int a, int b, int c)
m_a=1  m_b2
m_c=3
调用了基类的构造函数A(int a,int b)
调用了基类的拷贝构造函数A(const A &a)
调用了派生类的构造函数B(cosnt A &a,int c)
m_a=12  m_b22
m_c=23
调用了基类的析构函数
调用了基类的析构函数
调用了基类的析构函数
调用了基类的析构函数

 名字遮蔽是表象,类作用域是本质

 

 

 

 

 

B继承A

B b;

A *a=&b;

在C++中,数据类型决定了操作数据的方法,类似自定义的数据类型,类中有什么成员也属于操作数据的方法。

这里a是A类的指针,不管它指向谁,只会按A类的方法来操作数据。

就比如下面的代码,i是整型变量,a是类的指针,语法没有问题,编译不会报错,不过整型变量和A类的内存模型不匹配,运行报错。

#include "iostream"
using namespace std;
class A
{
    int m_b;

public:
    int m_a;
    void setb(int b)
    { 
        m_b = b;
    }
    void show()
    {
        cout << "m_a=" << m_a << ",m_b=" << m_b << endl;
    }
};
void test()
{
    int i;
    A *a = (A *)&i;
    a->m_a = 111;
    a->setb(11);
    a->show();
}
int main()
{
    test();
    return 0;
}

注意:

1 基类指针或引用只能调用基类的方法,不能调用派生类的方法。

2 可以用派生类构造基类

3 如果函数的形参是基类,实参可以用派生类

4 C++要求指针和引用类型与赋给的类型匹配,这一规则对继承来说是例外。但是,这种例外只是单向的,不可以将基类对象和地址赋给派生类引用和指针。

 

 菱形继承

 

#include "iostream"
using namespace std;
class A
{
public:
    int m_a;
};
class B : public A
{
};
class C : public A
{
};
class D : public B, public C
{
};
void test()
{
    D d;
    cout << "sizeof(d)=" << sizeof(d) << endl; //两个m_a成员,所以是8字节
    //如果直接访问m_a成员,将报错
    // d.m_a;//D::m_a" 不明确
    d.B::m_a = 100;
    d.C::m_a = 200;
    cout << "B::m_a的地址是:" << &d.B::m_a << "值是:" << d.B::m_a << endl;
    cout << "C::m_a的地址是:" << &d.C::m_a << "值是:" << d.C::m_a << endl;
    //菱形继承存在两个问题:数据冗余和名称的二义性,为了解决这两个问题,C++引入虚继承技术
}
int main()
{
    test();
    return 0;
}
sizeof(d)=8
B::m_a的地址是:0x61fde8值是:100
C::m_a的地址是:0x61fdec值是:200

菱形继承存在两个问题:数据冗余和名称的二义性,为了解决这两个问题,C++引入虚继承技术

 

 

#include "iostream"
using namespace std;
class A
{
public:
    int m_a;
};
class B : virtual public A
{
};
class C : virtual public A
{
};
class D : public B, public C
{
};
void test()
{
    D d;
    cout << "sizeof(d)=" << sizeof(d) << endl; //两个m_a成员,所以是8字节
    //如果直接访问m_a成员,将报错
    // d.m_a;//D::m_a" 不明确
    // d.B::m_a = 100;
    // d.C::m_a = 200;
    d.m_a = 300;
    cout << "B::m_a的地址是:" << &d.B::m_a << "值是:" << d.B::m_a << endl;
    cout << "C::m_a的地址是:" << &d.C::m_a << "值是:" << d.C::m_a << endl;
    //菱形继承存在两个问题:数据冗余和名称的二义性,为了解决这两个问题,C++引入虚继承技术
}
int main()
{
    test();
    return 0;
}
// sizeof(d)=24
// B::m_a的地址是:0x61fde0值是:300
// C::m_a的地址是:0x61fde0值是:300

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值