C++函数重载、覆盖、隐藏

最近公司招人,发现好多C++面试者基础概念理不清楚。今天恰好有点时间,把这些梳理下。有人读到的话也算为大家做点贡献,哈哈。

1, 函数重载(overload)

如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载(overloaded)函数。

void print(const char *p);
void print(const int *beg, const int *end);
void print(const int ia[], size_t size);  

 这些函数接受的形参类型或个数不一样,但是执行的操作非常类似。当调用这些函数时,编译器会根据传递的实参类型推断想要的是哪个函数。函数的名字仅仅是让编译器知道它调用的是哪个函数,而函数重载可以在一定程度上减轻程序员起名字、记名字的负担。

关键提取:同一作用域、函数名相同形参列表不同(类型或者个数)

//重载和const形参
//顶层的const不影响传入函数的对象
Record lookup(Phone);
Record lookup(const Phone); //重复声明了Record lookup(Phone)

Record lookup(Phone*);
Record lookup(const Phone*); //重复声明了Record lookup(Phone*)

//如果形参是某种类型的指针或者引用,则通过区分其指向的是常量对象还是非常量对象可以实现函数重载,此时的const是底层的
Record lookup(Account&);
Record lookup(const Account&); //新函数,作用于常量引用

Record lookup(Account*);
Record lookup(const Account*); //新函数,作用于指向常量的指针

//当我们传递一个非常量对象或者指向非常量对象的指针时,编译器会优先选用非常量版本的函数

2,覆盖(override)  

在基类(base class)和派生类(derived class)之间,基类有虚函数 virtual void fun(),派生类重新编写改函数 void fun() override,则为派生类覆盖从基类继承而来的定义。这个跟多态相关,详见https://www.cnblogs.com/baichenshan/p/8901819.html

class CBase
{
public:
    virtual void fun();  
}

class CDerived : public CBase
{
public:
    void fun() override; //覆盖基类的fun函数
}  

关键提取:关系是多个类之间,基类改函数必须是虚函数(virtual)

3,函数隐藏

派生类能重用定义在基类中的名字,此时定义在内层作用域(即派生类)的名字将隐藏定义在外层作用域(即基类)的名字。

如果派生类的成员与基类的某个成员同名,则派生类将在其作用域内隐藏该基类成员。即使派生类成员和基类成员的形参不一致,基类成员也仍然会被隐藏。

class CBase
{
public:
    void fun();  
}

class CDerived : public CBase
{
public:
    void fun() ; //派生类作用域内隐藏基类的fun函数
} 

关键提取:关系是多个类之间,派生类和基类函数名相同,函数无virtual修饰,形参可不相同

综合思考

class Base 
{
public:
    virtual int fcn();
};

class D1 : public Base
{
public:
    // 隐藏基类的 fcn, 这个 fcn 不是虚函数。 D1 继承了 Base::fcn() 的定义
    int fcn(int);    // 形参列表与Base中的fcn不一致
    
    virtual void f2();    // 是一个新的虚函数,在 Base 中不存在    
};

class D2 : public D1 
{
public:
    int fcn(int);    // 是一个非虚函数,隐藏了 D1::fcn(int)
    int fcn();    // 覆盖了 Base 的虚函数 fcn
    void f2();    // 覆盖了 D1 的虚函数 f2
}

///////////////////////////////////////////////////////////////////////////
Base bobj; D1 d1obj; D2 d2obj;
Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;
bp1->fcn();  // 虚调用,将在运行时调用 Base::fcn
bp2->fcn();  // 虚调用,将在运行时调用 Base::fcn
bp3->fcn();  // 虚调用,将在运行时调用 D2::fcn
bp2->f2();  // 错误:Base没有名为f2的成员

D1 *d1p = &d1obj; D2 *d2p = &d2obj;
d1p->f2();  //  虚调用,将在运行时调用 D1::f2
d2p->f2();  //  虚调用,将在运行时调用 D2::f2

Base *p1 = &d2obj; D1 *p2 = &d2obj; D2 *p3 = &d2obj;
p1->fcn(42);  // 错误:Base中没有接受一个int的fcn
p2->fcn(42);  // 静态绑定,调用 D1::fcn(int)
p3->fnc(42);  // 静态绑定,调用 D2::fcn(int)   

以上内容皆来自 C++ Primer , 多看书,多思考,多练习,基础自然扎实。

猜你喜欢

转载自www.cnblogs.com/baichenshan/p/9317902.html