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
类Base中加了Virtual关键字的函数就是虚拟函数(例如函数print),于是在Base的派生类Derived中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖。当基类Base的指针point指向派生类Derived的对象时,对point的print函数的调用实际上是调用了Derived的print函数而不是Base的print函数。这是面向对象中的多态性的体现
这也许会使人联想到函数的重载,但稍加对比就会发现两者是完全不同的:
(1) 重载的几个函数必须在同一个类中;
覆盖的函数必须在有继承关系的不同的类中
(2) 覆盖的几个函数必须函数名、参数、返回值都相同;
重载的函数必须函数名相同,参数不同。参数不同的目的就是为了在函数调用的时候编译器能够通过参数来判断程序是在调用的哪个函数。这也就很自然地解释了为什么函数不能通过返回值不同来重载,因为程序在调用函数时很有可能不关心返回值,编译器就无法从代码中看出程序在调用的是哪个函数了。
(3) 覆盖的函数前必须加关键字Virtual;
只有在通过基类指针或引用间接指向派生类子类型时多态性才会起作用
纯虚函数:
C++语言为我们提供了一种语法结构,通过它可以指明,一个虚拟函数只是提供了一个可被子类型改写的接口。但是,它本身并不能通过虚拟机制被调用。这就是纯虚拟函数(pure virtual function)。 纯虚拟函数的声明如下所示:
- class Query {
- public:
- // 声明纯虚拟函数
- virtual ostream& print( ostream&=cout ) const = 0;
- // ...
- };
这里函数声明后面紧跟赋值0。
包含(或继承)一个或多个纯虚拟函数的类被编译器识别为抽象基类。试图创建一个抽象基类的独立类对象会导致编译时刻错误。(类似地通过虚拟机制调用纯虚拟函数也是错误的例如)
- // Query 声明了纯虚拟函数
- // 所以, 程序员不能创建独立的 Query 类对象
- // ok: NameQuery 中的 Query 子对象
- Query *pq = new NameQuery( "Nostromo" );
- // 错误: new 表达式分配 Query 对象
- Query *pq2 = new Query;
抽象基类只能作为子对象出现在后续的派生类中。
如果只知道virtual加在函数前,那对virtual只了解了一半,virtual还有一个重要用法是virtual public,就是虚拟继承。虚拟继承在C++ Primer中有详细的描述,下面稍作修改的阐释一下:
在缺省情况下C++中的继承是“按值组合”的一种特殊情况。当我们写
- class Bear : public ZooAnimal { ... };
每个Bear 类对象都含有其ZooAnimal 基类子对象的所有非静态数据成员以及在Bear中声明的非静态数据成员类似地当派生类自己也作为一个基类对象时如:
- class PolarBear : public Bear { ... };
则PolarBear 类对象含有在PolarBear 中声明的所有非静态数据成员以及其Bear 子对象的所有非静态数据成员和ZooAnimal 子对象的所有非静态数据成员。在单继承下这种由继承支持的特殊形式的按值组合提供了最有效的最紧凑的对象表示。在多继承下当一个基类在派生层次中出现多次时就会有问题最主要的实际例子是iostream 类层次结构。ostream 和istream 类都从抽象ios 基类派生而来,而iostream 类又是从ostream 和istream 派生
- class iostream :public istream, public ostream { ... };
缺省情况下,每个iostream 类对象含有两个ios 子对象:在istream 子对象中的实例以及在ostream 子对象中的实例。这为什么不好?从效率上而言,存储ios 子对象的两个复本,浪费了存储区,因为iostream 只需要一个实例。而且,ios 构造函数被调用了两次每个子对象一次。更严重的问题是由于两个实例引起的二义性。例如,任何未限定修饰地访问ios 的成员都将导致编译时刻错误:到底访问哪个实例?如果ostream 和istream 对其ios 子对象的初始化稍稍不同,会怎样呢?怎样通过iostream 类保证这一对ios 值的一致性?在缺省的按值组合机制下,真的没有好办法可以保证这一点。
C++语言的解决方案是,提供另一种可替代按“引用组合”的继承机制虚拟继承(virtual inheritance )在虚拟继承下只有一个共享的基类子对象被继承而无论该基类在派生层次
中出现多少次共享的基类子对象被称为虚拟基类。
通过用关键字virtual 修政一个基类的声明可以将它指定为被虚拟派生。例如,下列声明使得ZooAnimal 成为Bear 和Raccoon 的虚拟基类:
- // 关键字 public 和 virtual的顺序不重要
- class Bear : public virtual ZooAnimal { ... };
- class Raccoon : virtual public ZooAnimal { ... };
虚拟派生不是基类本身的一个显式特性,而是它与派生类的关系如前面所说明的,虚拟继承提供了“按引用组合”。也就是说,对于子对象及其非静态成员的访问是间接进行的。这使得在多继承情况下,把多个虚拟基类子对象组合成派生类中的一个共享实例,从而提供了必要的灵活性。同时,即使一个基类是虚拟的,我们仍然可以通过该基类类型的指针或引用,来操纵派生类的对象。
没有虚函数的C++不能面向对象。从商业的角度看,面向对象能使系统具有可扩展性和可适应性,但只有C++类的语法而没有面向对象的话,就不会减少维护成本,而实际上会增加成本。所以没有虚函数是万万不能的,而关键字virtual则是关键
相关推荐
了解并掌握C++的关键字对于任何初学者来说都至关重要,因为这些关键字构成了语言的基础框架,直接影响到代码的编写和执行。 首先,我们要明白C++的关键字是用来控制程序流程、声明数据类型、创建类和对象、处理异常...
C++中的`virtual`关键字是实现多态性的重要机制,多态性允许程序在运行时决定调用哪个类的方法,而不是在编译时确定。在C++中,虚函数(virtual function)允许我们通过基类的指针或引用调用派生类中重写的方法,...
C++常用关键字详解 C++是一种功能强大且灵活的编程语言,它提供了一些常用的关键字来帮助开发者更方便地编写程序。这些关键字可以分为多种类别,如变量修饰符、流程控制、函数修饰符、访问修饰符等。下面,我们将...
1.virtual关键字主要是什么作用?c++中的函数调用默认不适用动态绑定。要触发动态绑定,必须满足两个条件:第一,指定为虚函数;第二,通过基类类型的引用或指针调用。由此可见,virtual主要主要是实现动态绑定。 2....
本文将详细介绍C++中的四种关键字,它们分别是`reinterpret_cast`、`static_cast`、`dynamic_cast`和`const_cast`,这四种关键字为程序员提供了安全且灵活的方式来执行不同类型之间的转换。 1. `reinterpret_cast` ...
C++关键字大全(67个) asm auto bad_cast bad_typeid bool break case catch char class const const_cast continue default delete do double dynamic_cast else enum except explicit extern false finally float ...
### C++关键字详解 在C++编程语言中,关键字具有特定的语法意义,它们由编译器识别并赋予特殊含义。下面将详细介绍一系列C++的关键字及其用途。 #### asm(汇编指令) - **功能**:`asm`关键字用于嵌入汇编代码到...
### C++基础关键字详解 #### 一、引言 C++是一种广泛使用的面向对象的编程语言,它在软件开发、系统编程以及高性能计算等领域扮演着重要角色。掌握C++的关键字是学习这门语言的基础。本文将详细介绍C++中的一些...
在C++中,纯虚函数的声明方式是使用virtual关键字,并在函数名后添加 "= 0",例如: ```cpp class Person { public: virtual void Eat() const = 0; // 纯虚函数 }; ``` 在上面的例子中,Eat()函数是一个纯虚函数,...
### C++中的关键字解析 #### 一、保留字与关键字 C++中存在大量预定义的标识符,这些标识符通常被称为保留字或关键字。它们具有特定的意义,并且被编译器用来识别语言结构的不同部分。例如,在C++中,“`auto`”、...
asm auto bad_cast bad_typeid bool break case catch char class const const_cast continue default delete do double dynamic_cast else enum except explicit extern...unsigned using virtual void volatile while
C++中的static关键字是一个非常重要的概念,它在不同的上下文中有不同的含义和用途。在C++中,使用static关键字可以修饰变量和函数,具有不同的作用。下面对这些知识点进行详细解释。 首先,静态变量(static ...
C语言32个关键字及其含义和C++63个关键字及其含义 C语言32个关键字及其含义: 1. auto:自动变量用关键字auto作存储类别的声明。(可以省略,不写则隐含确定为“自动存储类别”) 2. break:不能用于循环语句和...
C++是一种强大的面向对象编程语言,它包含了许多关键字来支持其复杂的语法和特性。下面将对标题和描述中提到的一些C++关键字进行详细解释: 1. **asm**: 在早期的C++版本中,`asm`关键字允许程序员在C++代码中嵌入...
在C++编程中,`virtual`关键字是实现多态性(Polymorphism)的关键机制,这对于理解和编写面向对象的代码至关重要。本篇将详细讲解C++中的`virtual`函数、构造函数与析构函数,以及继承与重写的概念。 1. `Virtual`...
C++是一种强类型、面向对象的编程语言,其关键字是语言语法的重要组成部分。在C++中,关键字具有特殊的含义,它们不能作为标识符(如变量名、函数名)使用。以下是一些C++的关键字及其用途的详细解释: 1. `asm`: ...
C++还有许多其他关键字,如`for`、`friend`、`goto`、`if`、`inline`、`new`、`namespace`、`operator`、`private`、`public`、`register`、`return`、`sizeof`、`static`、`struct`、`template`、`this`、`throw`、...
### C++关键字和操作符替代名 #### 概述 在C++编程语言中,关键字是具有特定含义的预定义标识符,它们被语言保留用于构成语法结构的关键部分。此外,C++还支持一系列操作符,包括算术、比较、逻辑等类型。为了提高...
18. `virtual`:`virtual`关键字用于声明虚函数,允许子类重写基类的行为。 19. `void`:`void`表示没有特定类型,常用于函数声明中表示不返回任何值,或在指针类型中表示不指向特定类型的数据。 20. `volatile`:...