当前位置: 首页 > wzjs >正文

广州番禺职业技术学院门户网站新手如何自己做网站

广州番禺职业技术学院门户网站,新手如何自己做网站,网站靠什么盈利,注册公司注册资金要实缴吗虚函数 什么是虚函数?虚函数示例解析代码解析: 使用虚函数的注意事项1. 虚函数的声明与定义2. 派生类中的虚函数 哪些函数不能声明为虚函数1. 普通函数(非成员函数)2. 构造函数3. 内联成员函数4. 静态成员函数5. 友元函数总结 纯虚…

虚函数

    • 什么是虚函数?
    • 虚函数示例解析
      • 代码解析:
    • 使用虚函数的注意事项
      • 1. 虚函数的声明与定义
      • 2. 派生类中的虚函数
    • 哪些函数不能声明为虚函数
      • 1. 普通函数(非成员函数)
      • 2. 构造函数
      • 3. 内联成员函数
      • 4. 静态成员函数
      • 5. 友元函数
      • 总结
    • 纯虚函数和抽象类
      • 示例
      • 输出结果
      • 作用
      • 使用场景
      • 注意事项
      • 示例代码解释

什么是虚函数?

虚函数是C++中实现多态性的关键机制。当指向基类的指针在操作它的多态类对象时,可以根据指向的不同类对象动态调用其相应的函数,这个函数就是虚函数。

在基类中定义虚函数后,可以在派生类中对虚函数进行重新定义,并且可以通过基类指针或引用,在程序运行阶段动态地选择调用基类和不同派生类中的同名函数。如果派生类中没有对虚函数重新定义,则它继承其基类的虚函数。

虚函数示例解析

让我们来分析一下给出的虚函数示例程序:

#include "stdafx.h"
#include<iostream>
using namespace std;class Base
{
public:virtual void Print()  // 基类虚函数{printf("This is Class Base!\n");}
};class Derived1 :public Base
{
public:void Print()  // 派生类1重写虚函数{printf("This is Class Derived1!\n");}
};class Derived2 :public Base
{
public:void Print()  // 派生类2重写虚函数{printf("This is Class Derived2!\n");}
};int main()
{Base Cbase;Derived1 Cderived1;Derived2 Cderived2;// 直接调用对象的方法Cbase.Print();Cderived1.Print();Cderived2.Print();cout << "---------------" << endl;// 通过基类指针调用方法Base *p1 = &Cbase;Base *p2 = &Cderived1;Base *p3 = &Cderived2;p1->Print();p2->Print();p3->Print();
}

程序输出:

This is Class Base!
This is Class Derived1!
This is Class Derived2!
---------------
This is Class Base!
This is Class Derived1!
This is Class Derived2!

代码解析:

  1. 首先,我们定义了一个基类 Base,其中包含一个虚函数 Print()
  2. 然后,我们定义了两个派生类 Derived1Derived2,它们都继承自 Base 并重写了 Print() 函数。
  3. main() 函数中,我们创建了三个对象:CbaseCderived1Cderived2
  4. 当我们直接调用对象的 Print() 方法时,每个对象都调用了自己类中定义的 Print() 函数。
  5. 然后,我们创建了三个基类指针,分别指向三个不同的对象。
  6. 关键在于:当我们通过基类指针调用 Print() 方法时,由于 Print() 是虚函数,程序会根据指针实际指向的对象类型来调用相应的函数。这就是多态的实现。

使用虚函数的注意事项

1. 虚函数的声明与定义

注意点: 只需要在声明函数的类体中使用关键字 virtual 将函数声明为虚函数,而定义函数时不需要使用关键字 virtual

具体例子:

// 正确的做法
class Animal {
public:virtual void makeSound(); // 在声明时使用virtual关键字
};// 定义时不需要使用virtual关键字
void Animal::makeSound() {cout << "Some generic animal sound" << endl;
}

在类外部定义虚函数时,不需要重复 virtual 关键字。如果类的声明和定义都在类体内,则只需要一次 virtual 关键字即可:

class Animal {
public:virtual void makeSound() { // 声明并定义,仅需一次virtual关键字cout << "Some generic animal sound" << endl;}
};

2. 派生类中的虚函数

注意点: 当将基类中的某一成员函数声明为虚函数后,派生类中的同名函数自动成为虚函数。

具体例子:

class Animal {
public:virtual void makeSound() {cout << "Some generic animal sound" << endl;}
};class Dog : public Animal {
public:// 此处无需使用virtual关键字,该函数自动成为虚函数void makeSound() {cout << "Woof!" << endl;}
};class Cat : public Animal {
public:// 同样,此处也无需使用virtual关键字void makeSound() {cout << "Meow!" << endl;}
};int main() {Animal* animals[3];animals[0] = new Animal();animals[1] = new Dog();animals[2] = new Cat();for(int i = 0; i < 3; i++) {animals[i]->makeSound(); // 动态绑定,调用对应派生类的函数}// 释放内存for(int i = 0; i < 3; i++) {delete animals[i];}return 0;
}

输出:

Some generic animal sound
Woof!
Meow!

尽管在 DogCat 类中没有使用 virtual 关键字,但 makeSound() 函数仍然被视为虚函数,并且能够通过基类指针正确调用对应的派生类函数。

哪些函数不能声明为虚函数

1. 普通函数(非成员函数)

无法声明为虚函数的原因:普通函数只能被重载(overload),不能被重写(override)。虚函数的目的是实现运行时多态,而普通函数没有关联的对象,无法在运行时根据对象类型做出不同的行为。

示例

#include <iostream>
using namespace std;// 错误 - 普通函数不能被声明为虚函数
// virtual void globalFunction() { cout << "Global function" << endl; }// 正确 - 普通函数可以重载但不能是虚函数
void globalFunction() { cout << "Global function" << endl; }
void globalFunction(int x) { cout << "Overloaded global function: " << x << endl; }int main() {globalFunction();globalFunction(10);return 0;
}

如果尝试将普通函数声明为虚函数,编译器会报错,因为虚函数需要一个虚函数表,而虚函数表必须与对象实例关联。

2. 构造函数

无法声明为虚函数的原因:构造函数的作用是初始化对象,在构造函数被调用时,对象尚未完全创建,虚函数表也尚未设置完成。此外,从语义上讲,构造函数是为了明确初始化对象成员,而虚函数是为了在不完全了解细节的情况下处理对象。

示例

#include <iostream>
using namespace std;class Base {
public:// 错误 - 构造函数不能是虚函数// virtual Base() { cout << "Base constructor" << endl; }// 正确 - 普通构造函数Base() { cout << "Base constructor" << endl; }
};class Derived : public Base {
public:Derived() { cout << "Derived constructor" << endl; }
};int main() {Derived d; // 先调用Base构造函数,再调用Derived构造函数return 0;
}

输出:

Base constructor
Derived constructor

构造函数的调用顺序是由继承关系决定的,从基类到派生类,这与虚函数的动态绑定机制不兼容。

3. 内联成员函数

无法声明为虚函数的原因:内联函数的目的是在编译时直接展开代码,减少函数调用开销,而虚函数是在运行时动态绑定的,这两个概念在实现上存在冲突。

示例

#include <iostream>
using namespace std;class Base {
public:// 声明为虚函数的内联函数 - 编译器会忽略inline关键字virtual inline void show() { cout << "Base show" << endl; }
};class Derived : public Base {
public:inline void show() override { cout << "Derived show" << endl; }
};int main() {Base* ptr = new Derived();ptr->show(); // 调用Derived::show(),内联特性被忽略delete ptr;return 0;
}

输出:

Derived show

在实际编译中,如果一个函数同时被声明为virtualinline,编译器会忽略inline特性,优先考虑虚函数的动态绑定特性。所以技术上可以同时使用这两个关键字,但实际上内联特性不会生效。

4. 静态成员函数

无法声明为虚函数的原因:静态成员函数属于类而非对象,所有对象共享同一份代码。虚函数通过对象的虚函数表实现动态绑定,而静态成员函数没有this指针,无法访问虚函数表。

示例

#include <iostream>
using namespace std;class Base {
public:// 错误 - 静态成员函数不能是虚函数// static virtual void staticFunction() { cout << "Base static function" << endl; }// 正确 - 普通静态成员函数static void staticFunction() { cout << "Base static function" << endl; }
};class Derived : public Base {
public:// 这是一个独立的静态函数,不是重写static void staticFunction() { cout << "Derived static function" << endl; }
};int main() {Base::staticFunction();    // 调用Base的静态函数Derived::staticFunction(); // 调用Derived的静态函数Base* ptr = new Derived();// 通过指针调用静态函数,实际上调用的是指针类型对应的类的静态函数ptr->staticFunction();     // 调用Base的静态函数delete ptr;return 0;
}

输出:

Base static function
Derived static function
Base static function

静态成员函数的调用在编译时就已确定,不会发生运行时的动态绑定。

5. 友元函数

无法声明为虚函数的原因:友元函数不是类的成员函数,而是被授予访问类的私有成员的外部函数。由于友元关系不能被继承,友元函数没有重写的概念,因此无法声明为虚函数。

示例

#include <iostream>
using namespace std;class Base {
private:int value = 10;// 错误 - 友元函数不能是虚函数// virtual friend void friendFunction(Base& obj) { cout << "Value: " << obj.value << endl; }// 正确 - 普通友元函数friend void friendFunction(Base& obj);
};void friendFunction(Base& obj) {cout << "Base value: " << obj.value << endl;
}class Derived : public Base {
private:int derivedValue = 20;// 这是一个新的友元函数,不是重写friend void friendFunction(Derived& obj);
};void friendFunction(Derived& obj) {cout << "Derived value: " << obj.derivedValue << endl;// 也可以通过Base类的友元函数访问基类部分的私有成员friendFunction(static_cast<Base&>(obj));
}int main() {Base b;Derived d;friendFunction(b);  // 调用Base的友元函数friendFunction(d);  // 调用Derived的友元函数return 0;
}

输出:

Base value: 10
Derived value: 20
Base value: 10

友元函数的调用是在编译时确定的,基于参数的静态类型,不会发生动态绑定。

总结

不能声明为虚函数的函数包括:

  1. 普通函数(非成员函数)- 缺少对象上下文
  2. 构造函数 - 对象尚未创建完成,无法动态绑定
  3. 内联成员函数 - 编译时展开与运行时绑定冲突(虽然可以同时使用关键字,但inline会被忽略)
  4. 静态成员函数 - 缺少this指针,无法访问虚函数表
  5. 友元函数 - 不是类的成员,无法继承也无法重写

纯虚函数和抽象类

纯虚函数是一种特殊的虚函数,它没有具体的实现,通常用于声明接口规范。其格式如下:

virtual 返回值类型 函数名(形参列表) = 0;
  • virtual 关键字表示这是一个虚函数。
  • = 0 表示这是一个纯虚函数,即没有具体的实现。

示例

以下是一个包含纯虚函数的基类和派生类的示例:

#include <iostream>
using namespace std;// 基类
class Base {
public:virtual void Print() = 0; // 纯虚函数
};// 派生类1
class Derived1 : public Base {
public:void Print() override { // 实现纯虚函数cout << "This is Class Derived1!" << endl;}
};// 派生类2
class Derived2 : public Base {
public:void Print() override { // 实现纯虚函数cout << "This is Class Derived2!" << endl;}
};int main() {Derived1 Cderived1;Derived2 Cderived2;Cderived1.Print(); // 调用派生类1的PrintCderived2.Print(); // 调用派生类2的Printcout << "---------------" << endl;Base *p1 = &Cderived1;Base *p2 = &Cderived2;p1->Print(); // 调用派生类1的Printp2->Print(); // 调用派生类2的Printreturn 0;
}

输出结果

This is Class Derived1!
This is Class Derived2!
---------------
This is Class Derived1!
This is Class Derived2!

作用

  1. 定义接口规范:纯虚函数主要用于定义接口规范,而将具体的实现留给派生类。它确保所有派生类都必须实现该函数,从而保证了多态的实现。
  2. 实现多态:通过纯虚函数,可以实现多态。在运行时,根据对象的实际类型调用对应的函数实现。
  3. 抽象类:包含纯虚函数的类称为抽象类。抽象类不能生成对象,但可以作为接口类,用于统一管理派生类对象。

使用场景

  • 抽象类:当基类中无法提供一个通用的实现,或者某些功能必须由派生类具体实现时,可以将函数定义为纯虚函数。
  • 多态:通过纯虚函数实现多态,可以在运行时根据对象的实际类型调用对应的函数实现。

注意事项

  1. 抽象类不能实例化:包含纯虚函数的类称为抽象类,抽象类不能生成对象。
  2. 派生类必须实现纯虚函数:如果派生类没有实现基类中的纯虚函数,则派生类也是抽象类,无法实例化。
  3. 纯虚函数不能被调用:纯虚函数没有具体的实现,因此不能直接调用。

示例代码解释

在上述代码中:

  • Base 类中的 Print 函数是一个纯虚函数,它没有具体的实现。
  • Derived1Derived2Base 的派生类,它们分别实现了 Print 函数。
  • main 函数中,通过基类指针调用派生类的 Print 函数,实现了多态。
http://www.dtcms.com/wzjs/425566.html

相关文章:

  • 做浏览单的网站有哪些搜索引擎优化排名技巧
  • 商城网站系统最近在线直播免费观看
  • 南京美容网站建设今日发生的重大新闻
  • 网站建设项目环境影响评价目录公司培训课程有哪些
  • wordpress中文版切换百度优化怎么做
  • 外国网站做问卷调查挣钱微信营销方法
  • 简单的网站代码搜索量用什么工具查询
  • 3 阐述网站建设的步骤过程北京债务优化公司
  • 网站平台建设总结如何在百度上添加自己的店铺
  • 网站标题正确书写标准网络营销的发展趋势
  • 个人的网站建设目标站长工具seo综合查询工具
  • WordPress 不显示主题页网站怎么优化关键词
  • 汕头网站制作电话优化营商环境 助推高质量发展
  • 凡科快图电脑版appstore关键词优化
  • 15个html5手机网站模板网站优化策略
  • 做网站要学哪些高清的网站制作
  • 网站做代理服务器网站收录查询站长工具
  • 网站导航图怎么做的详细步骤成人职业培训机构
  • 建网站需要怎样做郑州seo技术外包
  • 自己的网站怎么做商城石家庄百度搜索优化
  • 哪个网站做货车专业seo搜索优化软件
  • gif8.net基于wordpress西安seo管理
  • 网站锚点怎么用深圳疫情最新消息
  • 做那个类型的网站赚钱站长工具权重查询
  • 枣强网站建设代理山西seo谷歌关键词优化工具
  • 淘宝网站怎么做优化百度涨
  • 简约个人网站泰安短视频seo
  • 祥云网站建设数据分析师一般一个月多少钱
  • 普通的宣传网站用什么做2022最新版百度
  • 网站建设的安全措施福州网站seo优化公司