C++ 类(继承中的构造和析构)

文章概述

  1. 类型(赋值)兼容性原则;
  2. 类型(赋值)兼容性原则可以分为2个情况;
  3. 继承中的对象模型(内存模型);
  4. 继承中的构造析构调用原则;
  5. 继承和组合混搭下的构造和析构;
  6. 继承中同名的成员函数和成员变量处理方法;
  7. 继承中的static关键字

类型(赋值)兼容性原则

a. 类型(赋值)兼容性原则的说明: 需要基类对象的任何地方,都可以用公有派生类对象代替。通过公有继承,派生类得到了基类中除构造函数和析构函数以外的所有成员。实际上,公有派生类实际具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。
b. 类型(赋值)兼容性原则可以代替的情况:
这里写图片描述
代替之后,派生类对象可以直接作为基类的对象使用,但是只能用从派生类继承的成员。


类型(赋值)兼容性原则可以分为2个情况

a.第一个层次:

  • 基类指针(引用)指向子类对象
//P父类  C子类
P* p =NULL;
C c;
p =&s;
  • 父类指针做函数参数
void P(P* p);
  • 父类引用做函数参数
void P(P& p);

b.第二个层次:

  • 子类对象初始化父类对象
C c;
P p =c;
  • 子类对象赋值父类对象
C c;
P p;
p =c;

继承中的对象模型(内存模型)

a. 一个类中的对象模型:

class A
{
  protected:
  int a;
}

创建A类的对象时,会将成员函数和成员变量分开存储。a. 普通的成员变量存储在变量中; b. 静态的成员变量存储在全局区; c.成员函数存储在代码片段区。
b. 继承中的对象模型:

class A
{
   protected:
   int a;
}
class B:public A
{
   protected:
   int b;
}

这里写图片描述
(子类是由父类成员和新的子类成员叠加得到的)
问题: 对象b中对于变量a和b初始化是一样的吗???
不一样,子类对象构造时,需要调用父类的构造函数对其继承的成员变量初始化。子类对象析构时,会调用父类的析构函数对其继承的成员进行清理。—–》分工明确


继承中的构造析构调用原则

a. 子类对象在创建时会首先调用父类的构造函数;
b. 父类构造函数执行完毕后,执行子类的构造函数;
c. 当父类的构造函数中有参数时,必须在子类的初始化列表中显示调用;
d. 析构函数执行的顺序和构造函数的执行顺序相仿。

//写子类的构造函数时,必须要看看父类的构造函数能否被自动调用;
//若不能被自动调用,应该显示调用
class A
{
    int a;
public:
    A(int a)
    {
        this->a = a;
    }
};

class B:public A
{
    int b;
public:
    B(int b):A(10)
    {
        this->b = b;
    }
};

继承和组合混搭下的构造和析构

class C
{
    int c;
public:
    C(int c)
    {
        this->c = c;
        cout << "组合对象" << endl;
    }
};

class A
{
    int a;
public:
    A(int a)
    {
        this->a = a;
        cout << "父类" << endl;
    }
};

class B:public A
{
    int b;
    C c;
public:
    B(int b,int a,int c):A(a),c(c)
    {
        this->b = b;
        cout << "子类" << endl;
    }
};

int main()
{
    B b(20,10,5);
    return 0;
}

输出结果:
这里写图片描述
继承与组合对象混搭情况,构造与析构调用规则结论:
a. 先调用父类的构造函数,再调用组合对象的构造函数,最后调用自己的构造函数;
b. 先调用自己的析构函数,再调用组合对象的析构函数,最后调用父类的析构函数。


继承中同名的成员函数和成员变量处理方法

a. 当子类的成员变量和父类的成员变量同名时,子类依然从父类中继承同名变量,但是子类的同名变量会屏蔽父类的同名变量。子类中使用父类名+作用域符使用父类的同名成员变量。同名变量存储在不同的内存中。
b. 继承的同名成员变量和成员函数类似。

class A
{
    int x;
public:
    int a;
    A(int a)
    {
        this->a = a;
        cout << "父类" << endl;
    }
};

class B:public A
{
    int a;
public:
    B(int a,int b):A(a)
    {
        this->a = b;
        cout << "子类" << endl;
    }
    void printF()
    {
        cout << A::a << endl;
    }
};

int main()
{
    B b(20,10);
    cout << sizeof(b) << endl;
    A a(10);
    cout << sizeof(a) << endl;
    return 0;
}

对代码分析:
这里写图片描述


继承中的static关键字

a. 基类定义的静态成员将被所有的派生类共享;
b. 根据static成员自身的访问特性和派生类的继承方式,在类中具有不同的访问性质;
c. 派生类中访问静态成员,使用以下两种形式:

  • 类名::成员名
  • 对象名.成员名
    d. 初始化静态成员变量不是简单的初始化,要告诉C++编译器为静态变量分配内存;
    e. 单例中将构造函数设为私有的,不能在外部创建对象;别的情况应该将构造函数设为公有,不然无法创建对象。
class A
{
public:
    static int x;
    int a;
public:
    A(int a)
    {
        this->a = a;
        x +=10 ;
        cout << "父类" << endl;
    }
};

int A::x = 50;

class B:public A
{
    int a;
public:
    B(int a,int b):A(a)
    {
        this->a = b;
        x += 10;
        cout << "子类" << endl;
    }
    void printF()
    {
        cout << A::a << endl;
    }
};

int main()
{
    B b(20,10);
    cout << sizeof(b) << endl;
    A a(10);
    cout << sizeof(a) << endl;
    cout << A::x << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wue1206/article/details/81271039