一、函数重载初始

1.1 什么是函数重载

函数重载是C++中的重要特性,允许在同一作用域内声明多个同名函数,但这些函数的参数列表必须不同。具体来说,参数列表的区别可以体现在参数类型、参数个数或参数顺序上。

#include<iostream>
using namespace std;
void show(int x){cout<<"整数:"<<x<<endl;}
void show(double x){cout<<"浮点数:"<<x<<endl;}
void show(int x,double y){cout<<"两个参数:"<<x<<","<<y<<endl;}
int main(){
    show(10);
    show(3.14);
    show(5,2.5);
    return 0;
}

1.2 函数名修饰规则

C++编译器通过名称修饰来实现函数重载。不同编译器有不同的修饰规则:

GCC修饰规则示例:

  void func(int) → _Z4funci

  void func(double) → _Z4funcd

  void func(int, double) → _Z4funcid

Visual C++修饰规则示例:

   void func(int) → ?func@@YAXH@Z

   void func(double) → ?func@@YAXN@Z

1.3 函数重载的核心规则

1.3.1 有效的重载条件

class Calc{
public:
    int add(int a,int b){return a+b;}
    double add(double a,double b){return a+b;}
    int add(int a,int b,int c){return a+b+c;}
};

1.3.2 无效的重载情况

class ErrorExample{
public:
    void process(int x){}
    //int process(int x){} //错误:仅返回类型不同
    //void process(const int x){} //错误:const不构成重载
};

二、函数重载的实现细节

2.1 参数类型的精确匹配

#include<iostream>
using namespace std;
void display(char c){cout<<"字符:"<<c<<endl;}
void display(int i){cout<<"整数:"<<i<<endl;}
void display(const char* s){cout<<"字符串:"<<s<<endl;}
int main(){
    display('A');
    display(100);
    display("Hello");
    return 0;
}

2.2 常量成员函数重载

class Array{
    int data[10];
public:
    int get(int index){return data[index];}
    int get(int index)const{return data[index];}
};

2.3 默认参数与重载的交互

class Config{
public:
    void setValue(int a){cout<<"一个参数:"<<a<<endl;}
    void setValue(int a,int b=10){cout<<"两个参数:"<<a<<","<<b<<endl;}
};
void testConfig(){
    Config cfg;
    //cfg.setValue(5); //歧义错误
    cfg.setValue(5,20); //明确调用
}

三、调用约定详解

3.1 常见调用约定类型

#include<iostream>
using namespace std;
extern "C" void c_func(int x); //C调用约定
void __stdcall std_func(int x); //标准调用约定
void __fastcall fast_func(int x); //快速调用约定
void __cdecl cpp_func(int x); //C++默认约定
class Test{
public:
    void __thiscall member_func(); //成员函数约定
};

3.2 调用约定的实际影响

int __cdecl cdecl_add(int a,int b){return a+b;}
int __stdcall stdcall_add(int a,int b){return a+b;}
void demo(){
    int r1=cdecl_add(1,2); //调用者清理栈
    int r2=stdcall_add(1,2); //被调用者清理栈
    cout<<"结果:"<<r1<<","<<r2<<endl;
}

四、函数重载的实战应用

4.1 数学运算类实现

class Math{
public:
    static int max(int a,int b){return a>b?a:b;}
    static double max(double a,double b){return a>b?a:b;}
    static int max(int a,int b,int c){return max(max(a,b),c);}
    static int max(const int arr[],int size){
        int m=arr[0];
        for(int i=1;i<size;i++)if(arr[i]>m)m=arr[i];
        return m;
    }
};
int main(){
    cout<<Math::max(1,2)<<endl;
    cout<<Math::max(1.1,2.2)<<endl;
    cout<<Math::max(1,2,3)<<endl;
    int arr[]={1,5,3,7,2};
    cout<<Math::max(arr,5)<<endl;
    return 0;
}

4.2 字符串处理工具

class StringUtil{
public:
    static void format(char* buf,const char* fmt){sprintf(buf,"%s",fmt);}
    static void format(char* buf,const char* fmt,int val){sprintf(buf,fmt,val);}
    static void format(char* buf,const char* fmt,double val){sprintf(buf,fmt,val);}
    static void format(char* buf,const char* fmt,const char* val){sprintf(buf,fmt,val);}
};
void testStringUtil(){
    char buffer[100];
    StringUtil::format(buffer,"消息:%s","Hello");
    cout<<buffer<<endl;
    StringUtil::format(buffer,"数字:%d",42);
    cout<<buffer<<endl;
}

4.3 智能指针模拟

template<typename T>
class SmartPtr{
    T* ptr;
public:
    SmartPtr(T* p=nullptr):ptr(p){}
    T& operator*(){return *ptr;}
    T* operator->(){return ptr;}
    operator bool()const{return ptr!=nullptr;}
};
void demoSmartPtr(){
    SmartPtr<int>p1(new int(10));
    SmartPtr<double>p2(new double(3.14));
    if(p1)cout<<"值:"<<*p1<<endl;
    if(p2)cout<<"值:"<<*p2<<endl;
}

五、注意事项和最佳实践

5.1 避免歧义调用

class Problem{
public:
    void compute(int a,double b=0.0){}
    void compute(int a){}
};
void testProblem(){
    Problem p;
    //p.compute(5); //歧义错误
    p.compute(5,1.0); //正确
}

5.2 模板函数重载

template<typename T>
void process(T value){cout<<"模板:"<<value<<endl;}
void process(int value){cout<<"特化:"<<value<<endl;}
void testTemplate(){
    process(10); //调用特化版本
    process(10.5); //调用模板版本
    process("text"); //调用模板版本
}

5.3 继承中的重载

class Base{
public:
    virtual void execute(int x){cout<<"Base int"<<endl;}
    virtual void execute(double x){cout<<"Base double"<<endl;}
};
class Derived:public Base{
public:
    using Base::execute; //引入基类重载
    void execute(const char* x){cout<<"Derived string"<<endl;}
};
void testInheritance(){
    Derived d;
    d.execute(10); //调用基类版本
    d.execute(3.14); //调用基类版本
    d.execute("text"); //调用派生类版本
}

六、常见面试题精讲

6.1 基础概念题

题目1: 下面代码能否编译?为什么?

void func(int a){}
void func(const int a){}

答案: 不能编译,因为const不构成重载条件。

题目2: 以下哪个是有效的函数重载?

A. void test(int a) 和 int test(int a)
B. void test(int a) 和 void test(int a, int b=10)
C. void test(int a) 和 void test(double a)

答案: C

6.2 代码分析题

题目3: 分析以下代码输出结果

#include<iostream>
using namespace std;
void print(int i){cout<<"int:"<<i<<endl;}
void print(char c){cout<<"char:"<<c<<endl;}
int main(){
    print(65);
    print('A');
    return 0;
}

答案:int:65       char:A

6.3 高级理解题

题目4: 解释下面代码的行为

class Test{
public:
    static void show(int x){cout<<"static"<<endl;}
    void show(double x){cout<<"member"<<endl;}
};
int main(){
    Test::show(5);
    Test t;
    t.show(5.0);
}

答案: 静态函数和成员函数可以形成重载,通过不同调用方式区分。

6.4 实际应用题

题目5: 设计一个Logger类,支持不同级别的日志输出

class Logger{
public:
    enum Level{INFO,WARN,ERROR};
    void log(const string& msg){log(INFO,msg);}
    void log(Level level,const string& msg){
        cout<<"["<<levelToString(level)<<"]"<<msg<<endl;
    }
    void log(Level level,const string& msg,const string& file,int line){
        cout<<"["<<levelToString(level)<<"]"<<file<<":"<<line<<" "<<msg<<endl;
    }
private:
    string levelToString(Level level){
        switch(level){
            case INFO:return "INFO";
            case WARN:return "WARN";
            case ERROR:return "ERROR";
            default:return "UNKNOWN";
        }
    }
};

总结

函数重载是C++多态性的重要体现,通过深入理解名称修饰规则、调用约定和重载解析过程,可以编写出更加灵活和健壮的代码。在实际开发中,要注意避免歧义调用,合理设计函数接口,并充分考虑与模板、继承等特性的交互作用。

掌握函数重载不仅有助于通过技术面试,更是提升C++编程能力的关键一步。建议通过实际项目不断练习,加深对这一重要特性的理解和运用。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐