基类指针可以指向派生类对象,但是通过基类指针只能调用基类的成员函数,访问基类的成员变量,不能调用派生类的成员函数,也不能访问访问派生类的成员变量。
#include<iostream>
using namespace std;
class CAllComers{
public:
int m_bh=0;
void show(){
cout<<"CAllComers::show()我是"<<m_bh<<"号。"<<endl;
}
};
class CGirl:public CAllComers{
public:
int m_age=0;
void show(){
cout<<"CGirl::show():我是"<<m_bh<<"号,"<<m_age<<"岁。"<<endl;
}
};
int main(){
CGirl g;
g.m_bh=8;
g.m_age=23;
g.show();
CAllComers*pa=&g;
pa->show();
return 0;
}
CGirl::show():我是8号,23岁。
CAllComers::show()我是8号。
--------------------------------
Process exited after 0.518 seconds with return value 0
请按任意键继续. . .
如果基类函数是虚函数,当用基类指针指向派生对象时,会调用派生类中同名的成员函数。
:在基类的show()成员函数前加virtual关键字,把他声明为虚函数-----再运行:
#include<iostream>
using namespace std;
class CAllComers{
public:
int m_bh=0;
virtual void show(){
cout<<"CAllComers::show()我是"<<m_bh<<"号。"<<endl;
}
};
class CGirl:public CAllComers{
public:
int m_age=0;
void show(){
cout<<"CGirl::show():我是"<<m_bh<<"号,"<<m_age<<"岁。"<<endl;
}
};
int main(){
CGirl g;
g.m_bh=8;
g.m_age=23;
g.show();
CAllComers*pa=&g;
pa->show();
return 0;
}
CGirl::show():我是8号,23岁。
CGirl::show():我是8号,23岁。
--------------------------------
Process exited after 0.5126 seconds with return value 0
请按任意键继续. . .
如果基类函数是虚函数,当用基类指针指向派生对象时,会调用派生类中同名的成员函数。
通过派生类中同名的成员函数,就可以访问派生类对象的成员变量。
#include<iostream>
using namespace std;
class CAllComers{
public:
int m_bh=0;
virtual void show(){
cout<<"CAllComers::show()我是"<<m_bh<<"号。"<<endl;
}
};
class CGirl:public CAllComers{
public:
int m_age=0;
void show(){
cout<<"CGirl::show():我是"<<m_bh<<"号,"<<m_age<<"岁。"<<endl;
}
};
int main(){
CAllComers a; a.m_bh=3;//创建基类对象,并对成员赋值
CGirl g; g.m_bh=8;g.m_age=23;//创建派生对象,并对成员赋值
CAllComers* p;//声明基类指针
p=&a;p->show(); //让基类指针指向基类对象,并调用虚函数。
p=&g;p->show(); //让基类指针指向派生对象,并调用虚函数。
;
return 0;
}
CAllComers::show()我是3号。
CGirl::show():我是8号,23岁。
--------------------------------
Process exited after 0.5233 seconds with return value 0
请按任意键继续. . .
测试证明:有了虚函数,基类指针指向基类对象时就使用基类的成员函数和数据,指向派生类时就使用派生类的成员函数和数据。
基类指针表现出了多种类型,这种现象称之为多态
注意事项:
1.只需在基类的函数声明中加virtual关键字,函数定义时不能加。
#include<iostream>
using namespace std;
class CAllComers {
public:
int m_bh=0;
virtual void show();
};
virtual void show() {
cout<<"CAllComers::show()我是"<<m_bh<<"号。"<<endl;
}
这样会报错,函数定义的时候不可以加virtual关键字 ,应如下:
#include<iostream>
using namespace std;
class CAllComers {
public:
int m_bh=0;
virtual void show();
};
void show() {
cout<<"CAllComers::show()我是"<<m_bh<<"号。"<<endl;
}
2.在派生类中重新定义虚函数时,函数特征要相同;
#include<iostream>
using namespace std;
class CAllComers{
public:
int m_bh=0;
virtual void show(){
cout<<"CAllComers::show()我是"<<m_bh<<"号。"<<endl;
}
};
class CGirl:public CAllComers{
public:
int m_age=0;
void show(){
cout<<"CGirl::show():我是"<<m_bh<<"号,"<<m_age<<"岁。"<<endl;
}
void func(){
cout<<"调用了func()函数\n";
}
};
int main(){
CAllComers a; a.m_bh=3;//创建基类对象,并对成员赋值
CGirl g; g.m_bh=8;g.m_age=23;//创建派生对象,并对成员赋值
CAllComers* p;//声明基类指针
//p=&a;p->show(); //让基类指针指向基类对象,并调用虚函数。
p=&g;p->show(); //让基类指针指向派生对象,并调用虚函数。
p->func();
return 0;
}
报错:发现func()函数是派生类中新增的,基类指针找不到他。
如果给派生类的show()函数增加一个参数,编译运行没问题,但是日志显示的是基类的show()函数,不是派生类的。
class CGirl:public CAllComers{
public:
int m_age=0;
void show(int a){
cout<<"CGirl::show():我是"<<m_bh<<"号,"<<m_age<<"岁。"<<endl;
}
};
CAllComers::show()我是8号。
--------------------------------
Process exited after 0.5254 seconds with return value 0
请按任意键继续. . .
把派生类的show()函数里面的参数删掉,就正常调用派生类的show()函数了;
class CGirl:public CAllComers{
public:
int m_age=0;
void show(){
cout<<"CGirl::show():我是"<<m_bh<<"号,"<<m_age<<"岁。"<<endl;
}
};
CAllComers::show()我是8号。
--------------------------------
Process exited after 0.5254 seconds with return value 0
请按任意键继续. . .
如果给派生类增加一个重载版本的show()函数,然后用基类指针调用重载版本的show()函数
#include<iostream>
using namespace std;
class CAllComers{
public:
int m_bh=0;
virtual void show(){
cout<<"CAllComers::show()我是"<<m_bh<<"号。"<<endl;
}
};
class CGirl:public CAllComers{
public:
int m_age=0;
void show(){
cout<<"CGirl::show():我是"<<m_bh<<"号,"<<m_age<<"岁。"<<endl;
}
void show(int a){
cout<<"CGirl::show(int a):我是"<<m_bh<<"号,"<<m_age<<"岁。"<<endl;
}
};
int main(){
CAllComers a; a.m_bh=3;//创建基类对象,并对成员赋值
CGirl g; g.m_bh=8;g.m_age=23;//创建派生对象,并对成员赋值
CAllComers* p;//声明基类指针
//p=&a;p->show(); //让基类指针指向基类对象,并调用虚函数。
p=&g;p->show(5); //让基类指针指向派生对象,并调用虚函数。
return 0;
}
也报错了;对基类指针来说,他不认识派生类中的重载函数,如果把基类的虚函数也增加这个重载版本,再编译就没问题了;
#include<iostream>
using namespace std;
class CAllComers{
public:
int m_bh=0;
virtual void show(){
cout<<"CAllComers::show()我是"<<m_bh<<"号。"<<endl;
}
virtual void show(int a){
cout<<"CAllComers::show(int a)我是"<<m_bh<<"号。"<<endl;
}
};
class CGirl:public CAllComers{
public:
int m_age=0;
void show(){
cout<<"CGirl::show():我是"<<m_bh<<"号,"<<m_age<<"岁。"<<endl;
}
void show(int a){
cout<<"CGirl::show(int a):我是"<<m_bh<<"号,"<<m_age<<"岁。"<<endl;
}
};
int main(){
CAllComers a; a.m_bh=3;//创建基类对象,并对成员赋值
CGirl g; g.m_bh=8;g.m_age=23;//创建派生对象,并对成员赋值
CAllComers* p;//声明基类指针
//p=&a;p->show(); //让基类指针指向基类对象,并调用虚函数。
p=&g;p->show(5); //让基类指针指向派生对象,并调用虚函数。
return 0;
}
CGirl::show(int a):我是8号,23岁。
--------------------------------
Process exited after 0.5254 seconds with return value 0
请按任意键继续. . .
在派生类中重新定义虚函数时,函数特征要相同;
3.在派生类中重新定义了虚函数的情况下,如果想使用基类的虚函数,可以加类名和域解析符。