设为首页 加入收藏

TOP

C++ Virtual关键字详解(一)
2018-04-13 06:06:22 】 浏览:26
Tags:Virtual 关键字 详解

Virtual是C++ OO机制中很重要的一个关键字。如下所示:只要是学过C++的人都知道在类Base中加了Virtual关键字的函数就是虚拟函数(例如下面例子中的函数print),于是在Base的派生类Derived中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖。当基类Base的指针point指向派生类Derived的对象时,对point的print函数的调用实际上是调用了Derived的print函数而不是Base的print函数。这是面向对象中的多态性的体现。

class Base  
{  
public:Base(){}  
public:  
       virtual void print(){cout<<"Base";}  
};  

class Derived:public Base  
{  
public:Derived(){}  
public:  
       void print(){cout<<"Derived";}  
};  

int main()  
{  
       Base *point=new Derived();  
       point->print();  
}   

Output:

Derived

这也许会使人联想到函数的重载,但稍加对比就会发现两者是完全不同的

1. 重载的几个函数必须在同一个类中

覆盖的函数必须在有继承关系的不同的类中

2. 几个函数必须函数名、参数、返回值都相同;

重载的函数必须函数名相同,参数不同。参数不同的目的就是为了在函数调用的时候编译器能够通过参数来判断程序是在调用的哪个函数。这也就很自然地解释了为什么函数不能通过返回值不同来重载,因为程序在调用函数时很有可能不关心返回值,编译器就无法从代码中看出程序在调用的是哪个函数了。

3. 覆盖的函数前必须加关键字Virtual;

重载和Virtual没有任何瓜葛,加不加都不影响重载的运作。

关于C++的隐藏规则:

我曾经听说过C++的隐藏规则:

1. 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual

关键字,基类的函数将被隐藏(注意别与重载混淆)。

2. 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual

关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。———-引用自《高质量C++/C 编程指南》林锐 2001。 这里,林锐博士好像犯了个错误。C++并没有隐藏规则,林锐博士所总结的隐藏规则是他错误地理解C++多态性所致。下面请看林锐博士给出的隐藏规则的例证:

#include 
  
     
class Base  
{  
public:  
virtual void f(float x){ cout << "Base::f(float) " << x << endl; }  
void g(float x){ cout << "Base::g(float) " << x << endl; }  
void h(float x){ cout << "Base::h(float) " << x << endl; }  
};  

class Derived : public Base  
{  
public:  
virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }  
void g(int x){ cout << "Derived::g(int) " << x << endl; }  
void h(float x){ cout << "Derived::h(float) " << x << endl; }  
};  

void main(void)  
{  
Derived d;  
Base *pb = &d;  
Derived *pd = &d;  
// Good : behavior depends solely on type of the object  
pb->f(3.14f); // Derived::f(float) 3.14  
pd->f(3.14f); // Derived::f(float) 3.14  
// Bad : behavior depends on type of the pointer  
pb->g(3.14f); // Base::g(float) 3.14  
pd->g(3.14f); // Derived::g(int) 3 (surprise!)  
// Bad : behavior depends on type of the pointer  
pb->h(3.14f); // Base::h(float) 3.14 (surprise!)  
pd->h(3.14f); // Derived::h(float) 3.14  
}   
  

林锐博士认为bp 和dp 指向同一地址,按理说运行结果应该是相同的,而事实上运行结果不同,所以他把原因归结为C++的隐藏规则,其实这一观点是错的。决定bp和dp调用函数运行结果的不是他们指向的地址,而是他们的指针类型。“只有在通过基类指针或引用间接指向派生类子类型时多态性才会起作用”(C++ Primer 3rd Edition)。pb是基类指针,pd是派生类指针,pd的所有函数调用都只是调用自己的函数,和多态性无关,所以pd的所有函数调用的结果都输出Derived::是完全正常的;pb的函数调用如果有virtual则根据多态性调用派生类的,如果没有virtual则是正常的静态函数调用,还是调用基类的,所以有virtual的f函数调用输出Derived::,其它两个没有virtual则还是输出Base::很正常啊,nothing surprise!

所以并没有所谓的隐藏规则,虽然《高质量C++/C 编程指南》是本很不错的书,可大家不要迷信哦。记住“只有在通过基类指针或引用间接指向派生类子类型时多态性才会起作用”。

纯虚函数:

C++语言为我们提供了一种语法结构,通过它可以指明,一个虚拟函数只是提供了一个可被子类型改写的接口。但是,它本身并不能通过虚拟机制被调用。这就是纯虚拟函数(pure

virtual function)。 纯虚拟函数的声明如下所示:

class Query {  
public:  
// 声明纯虚拟函数  
virtual ostream& print( ostream&=cout ) const = 0;  
// ...  
};  

这里函数声明后面紧跟赋值0。

包含(或继承)一个或多个纯虚拟函数的类被编译器识别为抽象基类。试图创建一个抽象基类的独立类对象会导致编译时刻错误。(类似地通过虚拟机制调用纯虚函数也是错误的)

// Query 声明了纯虚拟函数, 我们不能创建独立的 Query 类对象  
// 正确: NameQuery 是 Query 的派生类  
Query *pq = new NameQuery( "Nostromo" );  
// 错误: new 表达式分配 Query 对象  
Qu
编程开发网
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++11的新特性介绍 下一篇C++的ifstream中使用eof最后一个..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

最新文章

热门文章

C 语言

C++基础

windows编程基础

linux编程基础

C/C++面试题目