虚函数的总结
2005-04-10 17:30
183 查看
1。虚函数的定义
虚函数是为了更好的实现OO思想的多态性而引入的,即当父类指针指向不同的对象(属于子类或父类)时,调用的将是对象所属类定义的该函数的版本。也就是说同一语句在不同环境下产生不同的效果。
下面是验证代码:
#include <iostream.h>
class myParentsClass
{
public:
myParentsClass()
{
cout<<"myParentsClass::myParentsClass"<<endl;
}
void testFun()
{
cout<<"myParentsClass::testFun"<<endl;
fun();
}
virtual void fun()
{
cout<<"myParentsClass::fun()"<<endl;
}
~myParentsClass()
{
cout<<"myParentsClass::~myParentsClass"<<endl;
}
};
class myClass:public myParentsClass
{
public:
myClass()
{
cout<<"myClass::myClass"<<endl;
}
void fun()
{
cout<<"myClass::fun()"<<endl;
}
~myClass()
{
cout<<"myClass::~myClass"<<endl;
}
};
class mySonClass:public myClass
{
public:
mySonClass()
{
cout<<"mySonClass::mySonClass"<<endl;
}
void fun()
{
cout<<"mySonClass::fun()"<<endl;
}
~mySonClass()
{
cout<<"mySonClass::~mySonClass"<<endl;
}
};
int main()
{
myParentsClass *pClass=NULL;
myClass *pMe=NULL;
myParentsClass myParents;
myClass me;
mySonClass mySon;
// pMe=&myParents; //出错,子类指针不能指向父类对象
pClass=&myParents;
pClass->fun();
pClass=&me;
pClass->fun();
pClass=&mySon;
pClass->fun();
return 0;
}
什么时候适合定义某个函数为虚函数呢?
以上例子得出结论的是 该函数将要在子类中进行改写时
2。虚函数的传递性:
虚函数只向下传递并且不会产生中断,即不会因为子类中没有对虚函数定义而影响该子类的子类同名函数的虚特性。
首先验证 向下传递性质
在主函数中加入如下语句:
........
pMe=&mySon;
pMe->fun(); //具有虚特性,调用的是mySonClass的fun方法
.....
然后验证 不会中断
去掉fun()在myClass的定义.并再次定义一个子类如下:
class myGrandsonClass:pulblic mySonClass
{
public:
void fun()
{
cout<<"myGrandsonClass::fun()"<<endl;
}
};
在主函数中加入如下语句:
.........
mySonClass *pSon=NULL;
myGrandsonClass myGrandson;
pSon=&myGrandson;
pSon->fun(); //可以看到虚函数的特性并没有消失
...........
最后验证虚函数不具备向上传递的特性:
去掉myParentsClass中fun()的修饰符virtual,然后在myClass或者在mySonClass中的fun()前面加上virtual
观察结果。
然后在主函数中加入如下语句:
pMe=&mySon;//只在mySonClass中的fun()的前面加virtual
pMe->fun();
观察结果。
3.虚函数的其他应用
在主函数加入如下代码:
................
pClass=&myParents;
pClass->fun();
pClass->testFun();
pClass=&me;
pClass->fun();
pClass->testFun();
pClass=&mySon;
pClass->fun();
pClass->testFun();
.......................
观察结果可以发现:
testFun()方法也在随指针的指向改变而调用不同的fun()函数。而当去掉fun()前面的virtual时,结果又会不同
由此得出以下结论:
void testFun()
{
cout<<"myParentsClass::testFun"<<endl;
fun(); //这个地方默认是的实际上是this->fun()
//而不是myParentsClass::fun()
}
ps:对于理解 深入浅出MFC第三章会有帮助
又:在主函数中加入如下语句:
myParentsClass *pParents=new myClass();
delete pParents;
pParents=NULL;
观察结果。
可以发现 delete pParents; 并没有调用myParentsClass的析构函数。如果该析构函数负责一些该类动态分配的内存的回收的话,这个语句将会造成严重的后果(指针悬挂).
解决办法:把myParentsClass的析构函数声明为虚函数。
当然如果你并没有打算在子类或子类的子类中重新定义该类(子类....)的析构函数也就不用这末做了。
虚函数是为了更好的实现OO思想的多态性而引入的,即当父类指针指向不同的对象(属于子类或父类)时,调用的将是对象所属类定义的该函数的版本。也就是说同一语句在不同环境下产生不同的效果。
下面是验证代码:
#include <iostream.h>
class myParentsClass
{
public:
myParentsClass()
{
cout<<"myParentsClass::myParentsClass"<<endl;
}
void testFun()
{
cout<<"myParentsClass::testFun"<<endl;
fun();
}
virtual void fun()
{
cout<<"myParentsClass::fun()"<<endl;
}
~myParentsClass()
{
cout<<"myParentsClass::~myParentsClass"<<endl;
}
};
class myClass:public myParentsClass
{
public:
myClass()
{
cout<<"myClass::myClass"<<endl;
}
void fun()
{
cout<<"myClass::fun()"<<endl;
}
~myClass()
{
cout<<"myClass::~myClass"<<endl;
}
};
class mySonClass:public myClass
{
public:
mySonClass()
{
cout<<"mySonClass::mySonClass"<<endl;
}
void fun()
{
cout<<"mySonClass::fun()"<<endl;
}
~mySonClass()
{
cout<<"mySonClass::~mySonClass"<<endl;
}
};
int main()
{
myParentsClass *pClass=NULL;
myClass *pMe=NULL;
myParentsClass myParents;
myClass me;
mySonClass mySon;
// pMe=&myParents; //出错,子类指针不能指向父类对象
pClass=&myParents;
pClass->fun();
pClass=&me;
pClass->fun();
pClass=&mySon;
pClass->fun();
return 0;
}
什么时候适合定义某个函数为虚函数呢?
以上例子得出结论的是 该函数将要在子类中进行改写时
2。虚函数的传递性:
虚函数只向下传递并且不会产生中断,即不会因为子类中没有对虚函数定义而影响该子类的子类同名函数的虚特性。
首先验证 向下传递性质
在主函数中加入如下语句:
........
pMe=&mySon;
pMe->fun(); //具有虚特性,调用的是mySonClass的fun方法
.....
然后验证 不会中断
去掉fun()在myClass的定义.并再次定义一个子类如下:
class myGrandsonClass:pulblic mySonClass
{
public:
void fun()
{
cout<<"myGrandsonClass::fun()"<<endl;
}
};
在主函数中加入如下语句:
.........
mySonClass *pSon=NULL;
myGrandsonClass myGrandson;
pSon=&myGrandson;
pSon->fun(); //可以看到虚函数的特性并没有消失
...........
最后验证虚函数不具备向上传递的特性:
去掉myParentsClass中fun()的修饰符virtual,然后在myClass或者在mySonClass中的fun()前面加上virtual
观察结果。
然后在主函数中加入如下语句:
pMe=&mySon;//只在mySonClass中的fun()的前面加virtual
pMe->fun();
观察结果。
3.虚函数的其他应用
在主函数加入如下代码:
................
pClass=&myParents;
pClass->fun();
pClass->testFun();
pClass=&me;
pClass->fun();
pClass->testFun();
pClass=&mySon;
pClass->fun();
pClass->testFun();
.......................
观察结果可以发现:
testFun()方法也在随指针的指向改变而调用不同的fun()函数。而当去掉fun()前面的virtual时,结果又会不同
由此得出以下结论:
void testFun()
{
cout<<"myParentsClass::testFun"<<endl;
fun(); //这个地方默认是的实际上是this->fun()
//而不是myParentsClass::fun()
}
ps:对于理解 深入浅出MFC第三章会有帮助
又:在主函数中加入如下语句:
myParentsClass *pParents=new myClass();
delete pParents;
pParents=NULL;
观察结果。
可以发现 delete pParents; 并没有调用myParentsClass的析构函数。如果该析构函数负责一些该类动态分配的内存的回收的话,这个语句将会造成严重的后果(指针悬挂).
解决办法:把myParentsClass的析构函数声明为虚函数。
当然如果你并没有打算在子类或子类的子类中重新定义该类(子类....)的析构函数也就不用这末做了。
相关文章推荐
- JAVA常用函数总结分享。
- PHP 文件与目录操作函数总结
- JSTL常用函数总结
- C语言中返回错误信息的相关函数用法总结
- 实验八——函数定义及调用总结
- Php常用文件操作函数,正则表达式,个人学习总结
- C/C++ —语言判断数字或字符的函数总结
- C++ 有关于函数对象以及谓词部分练习以及知识点的总结
- 关于php中date()函数的使用总结及查询当前日期所在一周的起始、结束日期
- 常用JS验证函数总结
- python 字符串操作常用函数总结
- assert()函数用法总结
- C语言几个字符串处理函数的总结
- Qt5.9Creator登录界面函数总结(通过连接远程服务器数据库MySql5.7.17进行登录用户名和密码验证)
- Windows 各种计时函数总结(转)
- string 函数总结
- string 函数总结
- solr查询参数、语法、函数总结
- VC各类之间的调用函数总结