在c++中可以用基类指针指向其派生类,如果一个派生类继承多个父类,那么如何通过基类指针访问同名的成员呢?
如果基类A,基类B中都有函数fun(),派生类在同时继承A、B后在内存中根据继承的顺序分配内存,例如在继承列表中出现的是B,A,那么B中的成员在A的之前,当我们用B的指针去访问时候,编译器便将指针指向B的成员,同理用A的指针去访问,编译器便将指针指向A的成员。
class base1
{
public:
int val;
void fun()
{
cout<<"output from base1 "<<endl;
}
};
class base2
{
public:
string val;
void fun()
{
cout<<"output from base2 "<<endl;
}
};
class Deriver:public base1,public base2
{
};
Deriver同时继承base1,base2,他们都有同名函数fun(),这时候访问哪一个取决于指针的类型
Deriver *der=new Deriver;
base1 *p1=der;
p1->fun();
base2 *p2=der;
p2->fun();
输出:
output from base1
output from base2
我们知道我们要通过一个基类的指针访问派生类中和基类同名的成员的时候,需要将基类中同名的函数声明为虚函数这样就可以通过基类的指针访问派生类的同名成员了
class base1
{
public:
int val;
virtual void fun()
{
cout<<"output from base1 "<<endl;
}
};
class base2
{
public:
string val;
void fun()
{
cout<<"output from base2 "<<endl;
}
};
class Deriver:public base1,public base2
{
void fun()
{
cout<<"output from Deriver "<<endl;
}
};
然后通过基类的指针访问派生类的成员
Deriver *der=new Deriver;
base1 *p1=der;
p1->fun();
base2 *p2=der;
p2->fun();
结果输出:
因为base1中fun()声明为虚函数,用base1的指针去访问fun()的时候会访问到派生类中的成员,而base2中没有声明为虚函数,在访问时访问到了基类的成员。可以看到,在派生类中并没有显示的声明fun()为虚函数,当派生类中的成员函数在
- 函数名
- 返回值
- 参数
与基类都相同时,派生类的函数变覆盖了基类同名函数,但是任然可以通过base1::fun()限定符来访问积累中的成员,一般只有那些希望实现多态的函数采用virtual修饰,否则就会出现用上面那样,基类指针和派生类指针访问到的成员不同的情况造成混乱。
最后,只有通过指针和引用访问成员的时候才会出现多态。
总之,声明为虚函数,调用的时候取决于指向对象的类型,没有声明,调用取决于指针的类型。
析构函数为虚函数的情况
有了上面的讨论可以知道,当我们用一个基类的指针指向一个派生类的时候,如果函数声明为虚函数,那么就会根据具体是指向哪一个类来调用改函数,析构函数也是如此。当我们用指向派生类的基类指针进行delete操作的时候,如果析构函数声明为虚函数,那么就会以以下方式进行析构函数调用
- 调用自身的析构函数
- 调用类中非静态数据类型的析构函数
- 调用基类的析构函数
class base1
{
public:
virtual ~base1()
{
cout<<"output from base1 destructor"<<endl;
}
};
class base2
{
public:
~base2()
{
cout<<"output from base2 destructor"<<endl;
}
};
class Deriver:public base1
{
base2 b2;
~Deriver()
{
cout<<"output from Deriver destructor "<<endl;
}
};
然后以以下方式创建删除变量
Deriver *der=new Deriver;
base1 *p1=der;
p1->fun();
delete p1;
得到如下结果
如果将base2前面的static去掉,则不调用其析构函数结果为
可以看到base2的析构函数没有被调用。