函数重载和函数指针在一起

传智扫地僧课程学习笔记。


先梳理下函数指针的基础语法,

1,

void myfunc( int a, int b);
typedef void (myTypeFunc)(int a, int b);
myTypeFunc *myfuncp = NULL;


2,

void myfunc( int a, int b);
typedef void (*myPTypeFunc)(int a, int b);
myTypeFunc myfuncp = NULL;

//注意与1的区别,是*


3,

void (*myVarPFunc)( int a, int b);


然后就开始说了,

函数重载和函数指针在一起的时候,会怎么样呢?

会不会因为在函数调用的时候,根据不同的参数,就调用不同的函数呢?

其实是不会的,

因为函数指针自己本身就有确定的类型,

在调用的时候会执行严格的类型检查,

void myfunc( double a, double b)
{
	cout<<"double kill"<<endl;
	cout<<a<<endl<<b<<endl;
}
typedef void (*mypfunc)( int a, int b);
int main()
{
	mypfunc p = NULL;
	p = myfunc;
	p( 1.0, 2.0);
	system("pause");
	return 0;
}
这里会报错的哦!


ps:

typedef int(*PFUNC)(int a);
PFUNC p = func;

因为typedef的存在,PFUNC成为了一种类型,

<think>首先,用户的问题是:“我想理解虚函数重载普通函数重载的区别以及各自在面向对象编程中的作用。请问虚函数重载普通函数重载的区别及其在C++面向对象编程中的应用。” 我需要基于系统级指令来构建回答。关键点是: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,如[^1]。 - 结构清晰,逐步解决问题。 - 引用站内内容:有四个引用[^1]到[^4],我需要参考它们,但用户说“上述引用仅供参考”,所以我应该基于这些引用来支持我的回答。 引用内容: - [^1]:讨论了重载多态。重载是在同一作用域内声明多个同名函数,形参不同。多态通过虚函数实现,允许基类访问派生类函数。 - [^2]:虚函数是实现多态的关键,允许统一接口处理不同类型对象。讨论虚函数的重写重载机制。 - [^3]:虚函数多态性,动态联编依赖于虚函数,赋值兼容性允许基类指针调用派生类虚函数。 - [^4]:函数模板的例子,包括重载模板。 用户的问题是区分虚函数重载普通函数重载。在C++中,术语可能混淆: - 普通函数重载(Overload):在同一作用域内,函数名相同但参数列表不同(参数类型、数量或顺序)。 - 虚函数重载:这有点模糊。通常,虚函数涉及重写(Override),而不是重载。重写是派生类中重新定义基类的虚函数,以实现多态。 在引用[^2]中,提到“虚函数的重写(Override)重载(Overload)机制”。所以,我需要澄清: - 重载(Overload):适用于普通函数或成员函数,基于参数不同。 - 重写(Override):适用于虚函数,派生类覆盖基类虚函数,以实现运行时多态。 用户说“虚函数重载”,可能是个误称;在标准C++中,是“虚函数重写”。但在上下文中,我应该解释清楚。 所以,区别: 1. **普通函数重载(Overload)**:在编译时解析,基于函数签名。用于提供多个版本的函数,处理不同类型或数量的参数。 2. **虚函数重写(Override)**:在运行时解析,通过虚表实现多态。允许派生类提供特定实现。 在面向对象编程中的作用: - 重载:提高代码可读性灵活性,允许函数名相同但行为不同基于输入。 - 重写(虚函数):实现多态,允许基类指针或引用调用派生类方法,支持开闭原则(扩展开放,修改关闭)。 应用: - 重载:常见于实用函数、构造函数等,如数学函数处理不同数值类型。 - 虚函数重写:在继承体系中,如形状类有draw()虚函数,派生类如Circle、Rectangle覆盖它。 现在,构建回答结构: 1. **介绍**:简要解释重载函数重写(override)的概念。 2. **区别**:详细对比编译时 vs. 运行时、作用域、参数等。 3. **在面向对象编程中的作用**:分别说明。 4. **应用示例**:提供代码示例说明。 5. **生成相关问题**:在末尾添加相关问题。 使用中文回答。 行内数学表达式:如果有数学内容,如函数签名,但用户问题不涉及数学,所以可能不需要。如果提到参数,可以用$...$表示。 例如,函数签名:$void f(int x)$ 或类似。 独立公式:可能不需要,除非有公式。 引用:在回答中,当引用概念时,添加引用标识。如,“重载是在同一作用域内声明多个同名函数[^1]”。 引用[^1]到[^4]需要整合。 生成相关问题:在最后,添加“§§相关问题§§”部分,列出3-5个相关问题。 确保回答真实可靠。 大纲: - **开头**:直接回答问题,概述。 - **主体**: - 解释普通函数重载。 - 解释虚函数重写(澄清术语)。 - 对比区别:编译时 vs. 运行时、绑定方式、作用域等。 - 各自在OOP中的作用。 - 代码示例:简单C++代码展示重载重写。 - **结尾**:总结。 - **相关问题**:生成相关问题。 代码示例:使用代码块,如示例中所示。 在代码中,确保LaTeX正确,但代码是代码块,不是LaTeX。 现在,内容: 普通函数重载: - 定义:在同一作用域内,多个函数同名但参数不同。 - 作用:提供接口一致性,处理不同类型参数。 - 引用[^1]: “重载是在同一作用域内,可声明多个功能类似的同名函数,这些同名函数的形参必须不同” 虚函数重写: - 定义:派生类中重新定义基类的虚函数。 - 作用:实现多态,动态绑定。 - 引用[^2]: “虚函数(Virtual Function)是实现多态性(Polymorphism)的关键机制之一” - 引用[^3]: “动态联编依赖于虚函数” 区别: - 解析时间:重载在编译时,重写在运行时。 - 绑定:重载是静态绑定,重写是动态绑定。 - 参数:重载要求参数不同,重写参数必须相同(协变返回类型除外)。 - 作用域:重载在同一作用域,重写在继承体系中。 在OOP中的作用: - 重载:封装接口设计。 - 重写:多态继承。 应用示例: - 重载示例:如print函数处理intstring。 - 重写示例:基类Shape,虚函数draw(),派生类覆盖。 代码: ```cpp // 普通函数重载示例 void print(int i) { std::cout << "Integer: " << i << std::endl; } void print(std::string s) { std::cout << "String: " << s << std::endl; } // 虚函数重写示例 class Shape { public: virtual void draw() const { std::cout << "Drawing a shape" << std::endl; } }; class Circle : public Shape { public: void draw() const override { // override关键字C++11起 std::cout << "Drawing a circle" << std::endl; } }; ``` 在回答中,使用中文解释。 相关问题: 1. 虚函数重写重载在性能上有什么区别? 2. 在C++中,如何确保虚函数被正确重写? 3. 函数重载模板在泛型编程中如何协同工作? 4. 多态性在面向对象设计中的重要性是什么? 最后,添加引用标识。</think>### 虚函数重载普通函数重载的区别及其在C++面向对象编程中的应用 在C++面向对象编程中,普通函数重载(Function Overloading)函数重载(通常指虚函数重写,即 Override)是两种不同的机制,它们在作用、实现方式应用场景上有显著差异。下面我将逐步解释两者的区别,并说明各自在面向对象编程中的作用应用。回答基于C++标准,并结合引用内容进行说明。 #### 1. **基本概念澄清** - **普通函数重载(Overload)**:指在同一作用域内(如类内部或全局作用域),声明多个同名函数,但这些函数的参数列表必须不同(例如,参数类型、数量或顺序不同)。重载在编译时解析,编译器根据调用时的参数选择匹配的函数版本。这提高了代码的可读性灵活性[^1]。 - 例如:`$void print(int x)$` `$void print(double x)$` 是重载函数。 - **虚函数重载(通常指重写,Override)**:虚函数(Virtual Function)是实现多态性的关键机制。在继承体系中,派生类可以重新定义基类的虚函数(称为重写),参数列表必须相同(协变返回类型除外)。重写在运行时通过虚表(vtable)动态绑定,允许基类指针或引用根据实际对象类型调用派生类函数[^2][^3]。 - 例如:基类有 `$virtual void draw() const$`,派生类覆盖为 `$void draw() const override$`。 - **术语澄清**:用户提到的“虚函数重载”在标准C++中更准确称为“虚函数重写(Override)”,而“重载(Overload)”特指编译时多态。引用[^2]明确指出虚函数涉及重写重载机制,但两者本质不同。 #### 2. **主要区别对比** 下表总结了普通函数重载函数重写的关键区别(基于编译时运行时行为): | 特性 | 普通函数重载(Overload) | 虚函数重写(Override) | |------|--------------------------|------------------------| | **解析时间** | 编译时静态绑定(早期绑定),编译器根据调用上下文选择函数版本。 | 运行时动态绑定(后期绑定),通过虚表实现,实际函数在运行时确定[^3]。 | | **参数要求** | 参数列表必须不同(例如, `$int$` vs `$double$`),否则编译错误。 | 参数列表必须相同(派生类函数签名基类虚函数一致),否则不是重写(可能隐藏基类函数)。 | | **作用域** | 在同一作用域内(如类中或全局),不涉及继承。 | 在继承体系中,基类声明虚函数,派生类覆盖它。 | | **绑定方式** | 静态绑定:函数地址在编译时固定。 | 动态绑定:函数地址在运行时通过对象类型解析[^2]。 | | **关键字** | 无需特殊关键字,仅依赖函数签名。 | 基类使用 `$virtual$` 声明,派生类可用 `$override$`(C++11起)确保正确重写。 | | **性能影响** | 高效,无运行时开销。 | 有轻微运行时开销(虚表查找),但支持灵活的多态。 | 例如,在编译时,普通重载根据参数类型选择函数: - 调用 `$print(10)$` 匹配 `$void print(int)$`。 - 调用 `$print("hello")$` 匹配 `$void print(std::string)$`。 而虚函数重写依赖于对象类型: - 基类指针 `$Shape* s = new Circle();$` 调用 `$s->draw()$` 时,实际执行 `$Circle::draw()$`。 #### 3. **在面向对象编程中的作用** 两者都服务于代码复用抽象,但侧重点不同: - **普通函数重载的作用**: - **提高接口一致性**:允许函数名相同但处理不同类型数据,简化API设计。例如,数学库中 `$max$` 函数重载处理 `$int$`、`$double$` 等。 - **支持静态多态**:在编译时确定行为,适用于非继承场景,如工具函数或构造函数重载。 - 引用[^1]强调重载能“重载各种各样的函数”,增强代码可扩展性。 - **虚函数重写的作用**: - **实现运行时多态**:核心是允许基类接口调用派生类特定实现,支持“开闭原则”(对扩展开放,对修改关闭)。例如,在图形系统中,`$Shape$` 基类定义虚函数 `$draw()$`,派生类如 `$Circle$` 或 `$Rectangle$` 覆盖它,实现统一绘制接口[^3]。 - **动态链接**:通过基类指针管理不同子类对象,简化代码并提高可维护性。引用[^2]指出,虚函数“允许使用统一的接口来处理不同类型的对象”。 - **支持设计模式**:如工厂模式或策略模式,其中多态是基础。 #### 4. **应用示例** 以下C++代码示例演示了普通函数重载函数重写的实际应用: ```cpp #include <iostream> #include <string> using namespace std; // 示例1: 普通函数重载(编译时解析) class Printer { public: void print(int i) { // 重载版本1: 处理int cout << "Integer: " << i << endl; } void print(double d) { // 重载版本2: 处理double cout << "Double: " << d << endl; } }; // 示例2: 虚函数重写(运行时多态) class Shape { public: virtual void draw() const { // 基类虚函数 cout << "Drawing a generic shape." << endl; } }; class Circle : public Shape { public: void draw() const override { // 派生类重写虚函数 cout << "Drawing a circle." << endl; } }; int main() { // 普通重载应用 Printer p; p.print(5); // 调用print(int), 输出: Integer: 5 p.print(3.14); // 调用print(double), 输出: Double: 3.14 // 虚函数重写应用 Shape* shape = new Circle(); shape->draw(); // 运行时调用Circle::draw(), 输出: Drawing a circle. delete shape; return 0; } ``` - **普通重载分析**:`Printer` 类中的 `$print$` 函数根据参数类型在编译时选择,无继承关系。 - **虚函数重写分析**:`Circle` 覆盖 `Shape` 的 `$draw()$`,通过基类指针调用时,运行时动态绑定到派生类实现。这体现了多态性在OOP中的核心作用[^3]。 #### 5. **总结** - **普通函数重载**:适用于编译时多态,增强函数接口的灵活性,但不涉及继承。作用域内基于参数差异实现。 - **虚函数重写**:实现运行时多态,是继承体系的核心,通过动态绑定支持代码扩展。两者在OOP中互补:重载优化接口设计,重写实现对象行为的多态性。 - **最佳实践**:在类设计中,优先使用虚函数重写处理继承场景;在工具类中,使用重载简化调用。引用[^4]提到模板重载可处理特定类型,但虚函数更专注于多态。 理解这些区别能帮助您设计更健壮的面向对象系统。如果您有具体代码场景,我可以进一步分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值