类其实也是一种数据类型,也可以发生数据类型转换,不过这种转换只有在基类(父类)和派生类(子类)之间才有意义,并且只能将派生类赋值给基类,包括将派生类对象赋值给基类对象、将派生类指针赋值给基类指针、将派生类引用赋值给基类引用,这在 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不同了。