C++常见面试题(九)——派生类指针赋值给基类指针问题

在C++继承中,很容易遇到一个问题,那就是将派生类指针赋值给基类指针(向上转型)的情况,下面我们就来举例分析:

举一个多继承的例子:

#include <iostream>
using namespace std;
 
//基类A
class A {
public:
	A(int a);
public:
	void display();
protected:
	int m_a;
};
A::A(int a) : m_a(a) { }
void A::display() {
	cout << "Class A: m_a=" << m_a << endl;
}
 
//中间派生类B
class B : public A {
public:
	B(int a, int b);
public:
	void display();
protected:
	int m_b;
};
B::B(int a, int b) : A(a), m_b(b) { }
void B::display() {
	cout << "Class B: m_a=" << m_a << ", m_b=" << m_b << endl;
}
 
//基类C
class C {
public:
	C(int c);
public:
	void display();
protected:
	int m_c;
};
C::C(int c) : m_c(c) { }
void C::display() {
	cout << "Class C: m_c=" << m_c << endl;
}
 
//最终派生类D
class D : public B, public C {
public:
	D(int a, int b, int c, int d);
public:
	void display();
private:
	int m_d;
};
D::D(int a, int b, int c, int d) : B(a, b), C(c), m_d(d) { }
void D::display() {
	cout << "Class D: m_a=" << m_a << ", m_b=" << m_b << ", m_c=" << m_c << ", m_d=" << m_d << endl;
}
 
 
int main() {
	A *pa = new A(1);
	B *pb = new B(2, 20);
	C *pc = new C(3);
	D *pd = new D(4, 40, 400, 4000);
 
	cout << "-------更改前-----" << endl;
	pa->display();
	pb->display();
	pc->display();
	pd->display();
        cout << "-----------------------" << endl;
 
	cout << "--------更改后-----------" << endl;
    
	pa = pd;
	pa->display();
 
	pb = pd;
	pb->display();
 
	pc = pd;
	pc->display();
 
	pd->display();
	cout << "-----------------------" << endl;
 
	system("pause");
	return 0;
}

结果:

       该例中我们定义了多个对象指针,并尝试将派生类指针赋值给基类指针。与对象变量之间的赋值不同的是,对象指针之间的赋值并没有拷贝对象的成员,也没有修改对象本身的数据,仅仅是改变了指针的指向:

        在更改前,每个指针都指向对应类的对象,并且完成了对成员变量的赋值;

        接下来将派生类的指针pd依次赋给pa、pb、pc,由此可以发现:

        当我们将派生类指针 pd 赋值给基类指针 pa后,从运行结果可以看出,调用 display() 函数时虽然使用了派生类的成员变量,但是 display() 函数本身却是基类的。也就是说,将派生类指针赋值给基类指针时,通过基类指针只能使用派生类的成员变量,但不能使用派生类的成员函数,pb、pc也是同样的情况,这是为什么呢?

        a 本来是基类 A 的指针,现在指向了派生类 D 的对象,这使得隐式指针 this 发生了变化,也指向了 D 类的对象,所以最终在 display() 内部使用的是 D 类对象的成员变量,编译器虽然通过指针的指向来访问成员变量,但是却不通过指针的指向来访问成员函数:编译器通过指针的类型来访问成员函数。对于 pa,它的类型是 A,不管它指向哪个对象,使用的都是 A 类的成员函数,只不过该成员函数中使用的是D类对象的成员变量。

        总结一下:编译器通过指针来访问成员变量,指针指向哪个对象就使用哪个对象的数据;编译器通过指针的类型来访问成员函数,指针属于哪个类的类型就使用哪个类的函数。(针对非虚函数!)

补充:

    通过基类的对象、指针、引用只能访问从基类继承过去的成员  (包括成员变量和成员函数),不能访问派生类新增的成员。
    通过基类的引用或指针,调用基类/派生类的虚函数,要根据运行时根据指针或引用实际指向或引用的类型确定,调用非虚函数时,则无论基类指向的是何种类型,都调用基类的函数 。

————————————————
版权声明:本文为CSDN博主「ENSHADOWER」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ENSHADOWER/article/details/96638232

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值