虚析构函数 内嵌对象构造 指针

虚析构函数 内嵌对象构造 指针


虚析构函数

#include <iostream>
#include <string>
#pragma warning(disable:4996)
using namespace std;
class person
{
protected:
    char *name;
    int age;
    char sex;
public:
    person(char *, int, char);
    virtual void show();
     ~person()
    {
        delete []name;
        cout << "调用基类person的析构函数 " << endl;
    }
};
person::person(char *name, int age, char sex) :age(age), sex(sex)
{
    this->name = new char[strlen(name) + 1];
    strcpy(this->name, name);
    cout << "调用基类person的构造函数 " << endl;
}
void person::show()
{
    cout << "调用基类person的show()函数 " << endl;
}
class student:public person
{
protected:
    int ID;
    char *major;
public:
    student(char *name, int age, char sex, int ID, char *major);
    void show();
    ~student()
    {
        delete []major;
        cout << "调用一级派生类student的析构函数 " << endl;
    }
};
student::student(char *name, int age, char sex, int ID, char *major) :person(name, age, sex), ID(ID)
{
    this->major = new char[strlen(major) + 1];
    strcpy(this->major, major);
    cout << "调用一级派生类student的构造函数 " << endl;
}
void student::show()
{
    cout << "调用派生类student的show()函数 " << endl;
}
class graduate:public student
{
private:
    char *mentor;
public:
    graduate(char *name, int age, char sex, int ID, char *major, char *mentor);
    void show();
    ~graduate()
    {
        delete[]mentor;
        cout << "调用二级派生类student的析构函数 " << endl;
    }
};
graduate::graduate(char *name, int age, char sex, int ID, char *major, char *mentor) :student(name, age, sex, ID, major)
{
    this->mentor = new char[strlen(mentor) + 1];
    strcpy(this->mentor, mentor);
    cout << "调用二级派生类student的构造函数 " << endl;
}
void graduate::show()
{
    cout << "调用派生类graduate的show()函数 " << endl;
}
void main()
{
    person *a;
    a = new graduate("张三", 20, 'N', 2022, "通信", "jianaji");
    a->show();
    delete a;
}

  • 可见,此时的基类析构函数没有使用虚析构函数,然后在delete a的时候就直接调用基类的析构函数,而没有调用一级派生类和二级派生类的析构函数

  • 如果把代码改成:

virtual ~person()
{
delete []name;
cout << "调用基类person的析构函数 " << endl;
}

  • 这样执行的结果就为:

  • 可见,调用析构函数的时候发生了动态联编,调用了二级派生类的析构函数(进而自然会调用一级和基类析构函数)

  • 这里这句代码:

    person *a;
    a = new graduate("张三", 20, 'N', 2022, "通信", "jianaji");
  • 就不能直接a = new graduate;因为graduate没有支持无参构造函数,自然不能完成对象的初始化(详解在下面的指针的介绍)


有关析构函数

  • 如果不声明析构函数,系统会自动生成一个

~类名(){}   的析构函数

  • 如果类中存在new出的动态空间,则一定要定义一个析构函数

  • 析构函数也是一个public成员,可以不内联,但是不能显式调用

student::~student(){}

  • 析构函数没有参数,所以不能重载


内嵌对象的构造方式

#include <iostream>
using namespace std;
class A
{
public:
    A(){ cout << "调用A无参" << endl; }
    A(int a){ dataA = a; cout << "调用A有参" << endl; }
    A(double a){ dataA = a; cout << "调用A有参2" << endl; }
private:
    int dataA;
};
class B
{
public:
    B(A , A a3, int);
private:
    A a1, a2;
    int dataB;
};
B::B(A a1, A a2, int dataB) :dataB(dataB)
{
    this->a1 = a1;
    a2 = a2;
}
void main()
{
    A a1(5), a2(4);
    B b(a1, a2, 5);
}

  • 从执行结果来看,

this->a1=a1;
a2=a2;

  • 这两句话应该是调用了A的无参构造函数,那么这两句话究竟是在哪里执行的呢?实际上,这两句话执行的位置应该是构造函数加粗的部分

B::B(A a1, A a2, int dataB) : dataB(dataB)

  • 即初始化列表的部分,原因是组合类(派生类也是)在初始化列表的位置总会留下给内嵌对象对应的类的构造函数定义的地方,如果没有显式写出,那么系统会自动生成一个无参构造函数,即:(注意初始化列表里参数的调用顺序)

B::B(A a1, A a2, int dataB) :dataB(dataB), a1(), a2()
{
    this->a1 = a1;
    a2 = a2;
}
  • 而整个构造函数的调用机制应该是这样

先将实参a1a2(这里的a1和a2并不是B的对象的内嵌A类对象) 传递给形参,然后在B的构造函数内,调用A的无参构造函数对实际的B的内嵌对象进行初始化,最后再将this->a1this->a2(这里的a1和a2才是B类的内嵌A类对象) 的由实参传递来的值赋值给这两个对象,完成对B的对象的构造(这里涉及到拷贝构造函数,在这里不展开讨论)
整个过程类似于下面这段代码(当然除开拷贝构造函数部分)

#include <iostream>
using namespace std;
class A
{
    int dataA;
public:
    A(int a) :dataA(a){ cout << "调用A有参" << endl; }
    A(){ cout << "调用A无参" << endl; }
};
void main()
{
    A a(4);
    A a2;
    a2 = a;
}

  • 注意初始化列表的部分不能使用this指针,内嵌对象和新数据成员都不行

B::B(A a1, A a2, int dataB) :this->dataB(dataB), this->a1(a1)
{
    a2 = a2;
}
  • 声明中的形参没有任何实际价值:(A a3 和 A a2)

public:
    B(A , A a3, int);
B::B(A a1, A a2, int dataB) :dataB(dataB), a1(a1)
{
    a2 = a2;
}

有关指针

void main()
{
    int *a;
    cout<<&a<<endl;
    cout << a << endl;
}

  • 可以发现,在int a; 这句话的时候给指针a 了一块内存00A3FDDC 来存储a这个指针变量,而且这个指针变量的值为CCCCCCCC ,即这个指针指向了一个地址为CCCCCCCC 的不知名的内存,这块内存内究竟存的是什么东西我们并不清楚,但是应该是个int型的数据吗?(其实并不是这样的,里面存的是个未知的东西,可能是块无效的内存)

void main()
{
    int *a;
    cout<<&a<<endl;
    cout << a << endl;
    cout << *a << endl;
}
  • 这样就会出现程序运行错误!!cout << a << endl; 这句并没有办法完成!!

  • 如果我把代码改成:

void main()
{
    int *a = 0;
    cout<<&a<<endl;
    cout << a << endl;
}

  • 即使指针a 变成了空指针,即为不指向任何物理内存的指针,即指针的值为00000000,并不是指针指向00000000这个实际上的内存地址,应该是表示根本就没有存储地址,所以返回00000000猜测

  • 将指针a 变成了空指针的方法:

int * p = NULL;
int * p = 0;
  • 再改下代码:

void main()
{
    int * p;
    p = new int;
    cout << &p << endl;
    cout << p << endl;
    cout << *p << endl;
}

  • 指针p指向了一块叫011CC0C0的内存,并且内存中已经存了一个任意值的int类型的值

  • 再改下代码:

void main()
{
    int * p = 0;
    p = new int(10);
    cout << &p << endl;
    cout << p << endl;
    cout << *p << endl;
}

  • 实际上int 是一个类,而使用int aint a(10)int a=10等等这些语句的时候,实际上都是调用不同的构造函数对对象a进行初始化。可见,int 类是至少重载了无参有参两种构造函数的。

  • 解释int a=10的运行机制:应该是int a表示无参构造了一个对象a,这个无参构造给a了一个任意值,然后用10这个对象给a 赋值。

转载于:https://my.oschina.net/CRAZYZONE/blog/636108

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值