向上转型(子类指针赋值给父类指针)

类其实也是一种数据类型,也可以发生数据类型转换,不过这种转换只有在基类(父类)和派生类(子类)之间才有意义,并且只能将派生类赋值给基类,包括将派生类对象赋值给基类对象、将派生类指针赋值给基类指针、将派生类引用赋值给基类引用,这在 C++ 中称为向上转型(Upcasting)。相应地,将基类赋值给派生类称为向下转型(Downcasting)。

将派生类对象赋值给基类对象

赋值的本质是将数据写入内存中,类的内存只包括成员变量(先不考虑虚函数表指针,成员函数不存在赋值问题),类的赋值其实就是类中成员变量的赋值。在继承部分我们讲了,即使父类的private类型成员,在子类对象中都会被创建并调用父类构造函数进行初始化,只是子类对象不能对其访问。

用子类对象定义父类对象进行赋值模型,用父类对象给子类对象赋值是不行的
在这里插入图片描述

将派生类指针赋值给基类指针(引用和指针类似)

先说结论:同对象赋值一样只能子给父赋值。用子类指针给父类指针赋值后
(例如 pa = pb),父类指针(pa)可以访问子类的成员变量,但使用的成员函数依然是父类的成员函数。

下面说的成员变量和成员函数都是指从父类继承过来那部分

对象指针的赋值并没有修改对象本身数据,只是改变了指针指向。因此指针改变指向后可以访问子类的成员变量。但是对象的成员函数并不在对象的内存中存储,而是存放在全局数据区(包括全局变量,全局函数,可读写)。而成员函数的第一个参数实际上是this指针(被自动隐藏了),指针赋值后其类型并没有变化所以访问到的还是父类的成员函数。

向上转型后通过基类的对象、指针、引用只能访问从基类继承过去的成员(包括成员变量和成员函数),不能访问派生类新增的成员。

将派生类指针赋值给基类指针时到底发生了什么?

以下面模型为例子:A 派生 B ,D继承B和C
在这里插入图片描述

using namespace std;
class A{
public:
	A() :m_a(10), m_a1(11){}
	void func()
	{
		cout << "m-a " << this->m_a << " m-a1 " << this->m_a1 << endl;
	}
	int m_a;
private:
	int m_a1;
};
class B:public A{
public:
	B() :m_b(20), m_b1(21){}
	void func()
	{
		cout << "m-a "<<this->m_a<<" m-b " << this->m_b << " m-b1 " << this->m_b1 << endl;
	}
	int m_b;
private:
	int m_b1;
};
class C {
public:
	C() :m_c(30), m_c1(31){}
	void func()
	{
		cout  << "m-c " << this->m_c << " m-c1 " << this->m_c1 << endl;
	}
	int m_c;
private:
	int m_c1;
};
class D :public B,public C{
public:
	D() :m_d(40), m_d1(41){}
	void func()
	{
		cout << "m-a " << this->m_a << " m-b " << this->m_b <<
			"m-c " << this->m_c << " m-d " << this->m_d <<" m-d1 "<<this->m_d1<<endl;
	}
	int m_d;
private:
	int m_d1;
};

让ABC类指针指向D

	A*pa = new A;
	B*pb = new B;
	C*pc = new C;
	D*pd = new D;
	pa = pd;
	pb = pd;
	pc = pd;

指针指向同一位置,按理来说其地址都是一样的,我们来输出pa pb pc

cout << pa << " " << pb << " " << pc << " " << pd << " " << endl;
结果为:
0x2495c80 0x2495c80 0x2495c90 0x2495c80 

pa pb和pd的地址是一样的,pc的地址一样

为什么?
在进行赋值的时候,编译器会为我们进行类型检测和转换,当不能转换的时候编译器会报错,当能转换的时候,会替我们转换。如:

double pi = 3.14159;
    int n = pi;
    cout<<pi<<", "<<n<<endl;
    运行结果:
3.14159, 3

同样在进行指针赋值的时候也是如此。将子类指针赋值个父类指针,编译器会做如下处理:让指针指向对象的起始位置
在这里插入图片描述
上面是D的内存模型,B类对象和C类对象在内存中的先后顺序是依据继承时的顺序决定的。这就是为什么pa pb和pd的地址相同,pc和pd不同的原因
如果让D先继承C再继承B那么就是pc和pd地址相同 pa pb和pd不同了。

发布了145 篇原创文章 · 获赞 12 · 访问量 9656

猜你喜欢

转载自blog.csdn.net/weixin_44997886/article/details/104610140