当定义的子类继承父类并重写父类的方法后,
父类使用指针调用子类的同名方法,得到的却是父类同名方法的结果?
#include <iostream>
using namespace std;
class Father
{
public:
void play() {
cout << "一起去KTV唱歌吧" << endl;
};
};
class Son :public Father {
public:
void play() {
cout << "一起去打游戏吧!" << endl;
};
};
void testPlay(Father** man, int n) {
for (int i = 0; i < n; i++) {
man[i]->play();//man[i] = *man;
}
}
int main(void) {
Father father;
Son son1, son2;
Father* p[3] = { &father,&son1,&son2 };
int len = sizeof(p) / sizeof(p[0]);
testPlay(p, len);
}
是在父类方法声明的时候添加virtual关键字,实现的时候不需要添加
子类重写该方法的时候也可以添加,
父类
?virtual void play() {
?? ?cout << "一起去KTV唱歌吧" << endl;
};子类
virtual void play() {
?? ?cout << "一起打游戏吧!" << endl;
};
形式上,使用 统一的父类指针做一般性处理,
但是实际执行时,这个 指针可以指向子类对象,
形式上,原本调用父类的方法,但是 实际上会调用子类的同名方法。
注意:程序执行时,父类指针指向父类对象,或子类对象时,在形式上是无法分辨的!只有通过多态机制,才能执行真正对应的方法。
?
这里一个对象理应内存分布:一个虚函数指针+两个int成员数据(12个字节)
?//虚函数是存放在虚函数表里的
//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针
virtual void fun1() {cout << "virtual:fun1()" << endl;}
virtual void fun2() { cout << "virtual:fun2()" << endl; }
virtual void fun3() { cout << "virtual:fun3()" << endl; }//普通成员函数在代码区
void fun4() { cout << "非虚函数:fun1()" << endl; }public:
?? ?int x = 200;
?? ?int y = 300;static int z;//静态成员数据在内存的全局数据区
?
#include <iostream>
using namespace std;
class Father{
public:
//虚函数是存放在虚函数表里的
//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针
virtual void fun1() {cout << "Father:fun1()" << endl; }
virtual void fun2() { cout << "Father:fun2()" << endl; }
virtual void fun3() { cout << "Father:fun3()" << endl; }
//普通成员在代码区
void fun4() { cout << "非虚函数:Father::fun4()" << endl; }
int x = 200;
int y = 300;
static int z;//静态成员数据在内存的全局数据区
};
int Father::z = 0;
//定义一个void型函数指针
//virtual void fun1() {cout << "Father:fun1()" << endl;}
typedef void (*fun_t)(void);
int main(void) {
Father father;
cout << father.x << endl;
//一个虚函数大小
//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针,指向虚函数表
//理应,这里只占12个字节
cout << "sizeof(father)的大小:" << sizeof(father) << endl;
cout << "对象的地址" << (int*)&father << endl;
//先将father的值16进制的地址转换成int*的指针,在取值,然后再转换成int*的指针进行赋值
int* vptr = (int*)(*(int*)&father);
cout << "虚函数指针vptr的地址值" << vptr << endl;
cout << "调用第一个虚函数:";
((fun_t) * (vptr + 0))();//等同于调用void father::fun1(void);
cout << "调用第二个虚函数:";
((fun_t) * (vptr + 1))();//等同于调用void father::fun2(void);
cout << "调用第三个虚函数:";
((fun_t) * (vptr + 2))();//等同于调用void father::fun3(void);
cout << "第一个数据成员的地址:" << endl;
cout << &father.x << endl;
cout << std::hex << (int) & father + 4 << endl;
cout << "第一个数据成员的值:" << endl;
cout <<std::dec<< father.x << endl;
cout << *(int*)((int)&father + 4) << endl;
cout << "第二个数据成员的地址:" << endl;
cout << &father.y << endl;
cout << std::hex << (int) & father + 8 << endl;
cout << "第二个数据成员的值:" << endl;
cout << std::dec <<father.y << endl;
cout << *(int*)((int)&father + 8) << endl;
return 0;
}
直接复制父类的虚函数表
?在父类虚函数的对应位置进行替换
当父类再次指向子类的时候,子类中的虚函数表已经发生改变,父类这时候调用虚函数得到的就是子类的虚函数表中对应的东西
将新增的虚函数添加到已有虚函数表尾部
?
?
#include <iostream>
using namespace std;
class Father{
public:
//虚函数是存放在虚函数表里的
//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针
virtual void fun1() {cout << "Father:fun1()" << endl; }
virtual void fun2() { cout << "Father:fun2()" << endl; }
virtual void fun3() { cout << "Father:fun3()" << endl; }
//普通成员在代码区
void fun4() { cout << "非虚函数:Father::fun4()" << endl; }
int x = 200;
int y = 300;
static int z;//静态成员数据在内存的全局数据区
};
int Father::z = 0;
class Son :public Father {
public:
//继承父类的虚函数
virtual void fun1() { cout << "Son:fun1()" << endl; }
//自己的虚函数
virtual void fun4() { cout << "Son:fun4()" << endl; }
};
//定义一个void型函数指针
//virtual void fun1() {cout << "Father:fun1()" << endl;}
typedef void (*fun_t)(void);
int main(){
Son son;
int* vptr1 = (int*)*(int*)&son;
cout << "son的地址:" << (int*) & son << endl;
cout << "sizeof(son)的值:" << sizeof(son) << endl;
for (int i = 0; i < 4; i++){
cout << "调用第" << i + 1 << "个虚函数:";
((fun_t) * (vptr1 + i))();
}
for (int i = 1; i <= 2; i++){
cout << "第" << i << "个成员的值"<<endl;
cout << son.x << endl;
cout << *(int*)((int) & son + 4) * i << endl;
}
return 0;
}
?
#include <iostream>
using namespace std;
class Father{
public:
//虚函数是存放在虚函数表里的
//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针
virtual void fun1() {cout << "Father:fun1()" << endl; }
virtual void fun2() { cout << "Father:fun2()" << endl; }
virtual void fun3() { cout << "Father:fun3()" << endl; }
//普通成员在代码区
void fun4() { cout << "非虚函数:Father::fun4()" << endl; }
int x = 200;
int y = 300;
static int z;//静态成员数据在内存的全局数据区
};
int Father::z = 0;
//另外一个基类
class Monther {
public:
//虚函数是存放在虚函数表里的
//虚函数表没有占用对象的内存空间,对象内存空间中只有一个虚函数指针
virtual void handel() { cout << "Monther:handl()" << endl; }
virtual void hande2() { cout << "Monther:handl2()" << endl; }
//普通成员在代码区
void fun() { cout << "非虚函数:Father::fun4()" << endl; }
int m = 400;
int n = 600;
static int z;//静态成员数据在内存的全局数据区
};
class Son :public Father ,public Monther{
public:
//继承父类的虚函数
virtual void fun1() { cout << "Son:fun1()" << endl; }
//自己的虚函数
virtual void fun4() { cout << "Son:fun4()" << endl; }
//继承另外一个基类的虚函数
virtual void hande2() { cout << "Son:handl2()" << endl; }
};
//定义一个void型函数指针
//virtual void fun1() {cout << "Father:fun1()" << endl;}
typedef void (*fun_t)(void);
int main(){
Son son;
int* vptr1 = (int*)*(int*)&son;
cout << "第一个虚函数表的指针" << vptr1 << endl;
//第二个虚函数表
// 一个虚函数指针,两个成员数据
int* vptr2 = (int*)*((int*)&son+3);
cout << "第二个虚函数表的指针" << vptr2 << endl;
cout << "son的地址:" << (int*) & son << endl;
cout << "sizeof(son)的值:" << sizeof(son) << endl;
for (int i = 0; i < 4; i++){
cout << "调用第" << i + 1 << "个虚函数:";
((fun_t) * (vptr1 + i))();
}
for (int i = 1; i <= 2; i++){
cout << "第" << i << "个成员的值"<<endl;
cout << *(int*)((int) & son + 4 * i) << endl;
}
for (int i = 1; i <= 2; i++) {
cout << "继承母亲的第" << i << "个成员的值" << endl;
cout << *(int*)((int)&son +12+ 4 * i) << endl;
}
for (int i = 0; i < 2; i++) {
cout << "调用母亲的第" << i + 1 << "个虚函数:";
((fun_t) * (vptr2 + i))();
}
return 0;
}
?
class i1 {
};
class i2 final :public i1{};
class i3 :public i2{};
?
?class i1 {
?? ?virtual void chat()final {
?? ??? ?cout << "聊天一代" << endl;
?? ?};
};
class i2 ?:public i1 {
?? ?virtual void chat();
};
作用:1. 提示程序的阅读者,这个函数是重写父类的功能。2. 防止程序员在重写父类的函数时,把函数名写错。
class i1 {
public:
?? ?virtual void chat() {
?? ??? ?cout << "聊天一代" << endl;
?? ?};
};
class i2 ?:public i1 {
public:
?? ?virtual void chat()override;
};
#include <iostream>
#include <string>
using namespace std;
class Father {
public:
Father(const char* addr = "中国") {
cout << __FUNCTION__ << endl;
int len = strlen(addr) + 1;
this->addr = new char[len];
strcpy_s(this->addr,len, addr);
};
~Father() {
cout << __FUNCTION__ << endl;
if (addr) {
delete[] addr;
addr = NULL;
}
};
private:
char* addr;
};
class Son:public Father {
public:
Son(const char* addr = "中国",const char *game = "推箱子"):Father(addr) {
cout << __FUNCTION__ << endl;
int len = strlen(game) + 1;
this->game = new char[len];
strcpy_s(this->game, len, game);
};
~Son() {
cout << __FUNCTION__ << endl;
if (game) {
delete[] game;
game = NULL;
}
};
private:
char* game;
};
int main(void) {
string line(50, '-');
Father* father = new Father();
delete father;
cout << line << endl;
Son* son = new Son();
delete son;
cout << line << endl;
Father* father1 = new Son();
delete father1;
cout << line << endl;
}
?上述可以看出
父类的通过子类定义的对象,释放之后,只释放了父类的空间,子类并没有释放;
解决:将父类的析构函数定义为虚函数
作用:当对父类的指针进行delete的时候,就会对该指针使用"动态析构"[如果这个指针是指向子类对象,那么就会先调用该子类的析构函数,然后再调用父类的]
virtual ~Father() {?
?
纯虚数(仅提供接口,实际方法由子类实现)
抽象类(拥有纯虚数的的类就是抽象类),抽象类无法创建对象
?
//把eat方法定义为纯虚数
virtual void eat() = 0;
1:纯虚函数一定要被实现才会结束抽象这个类?,
2:要么不对这个纯虚函数做任何处理,等效于下一种情况(该方式不推荐)
3:要么继续把这个纯虚函数声明为纯虚函数,这个子类也成为抽象类virtual void eat() = 0;
#include <iostream>
#include <string>
using namespace std;
class Shape {
public:
Shape(const string& color = "白色") { this->color = color; }
string getColor()const {
return color;
}
//定义一个纯虚数
virtual float area() = 0;
private:
string color;
};
class Circle :public Shape {
public:
Circle(float radios, const string& color) :Shape(color),r(radios){};
//实现父类的纯虚数
float area() { return 3.14 * r * r; }
private:
float r;
};
int main(void) {
//Shape shape;
Circle cir(2,"白色");
cout<<cir.getColor()<<endl;
cout <<cir.area()<<endl;
}