重写(虚函数)、重载(同作用域同名函数)、隐藏(内外作用域同名函数)

这里写目录标题

1. 重写

针对虚函数,子类可以重写父类中声明的虚函数。

如果用父类的指针或引用来调用函数,那么会检查这个函数的静态类型是否被声明为virtual:

  • 如果是,那么将调用这个函数的动态类型的版本。所谓动态类型的版本,就是如果子类进行了重写,那么就是用重写后的版本, 如果没有重写,那么还是父类的版本。例如:
#include <iostream>

class Animal {
    
    
public:
    virtual void eat() {
    
    
        std::cout << "animal eat" << std::endl;
    }
};


class Dog : public Animal {
    
    
public:
    void eat(std::string food) {
    
    
        std::cout << "dog eat " << food << std::endl;
    }
};

int main() {
    
    

    Animal* ani = new Dog();
    /*
    ani是父类指针,eat()是virtual的,那么将调用动态版本:
        但是子类并没有重写eat(),所以子类的eat()依然是父类版本。
        因此打印的是animal eat。

        这里并不会产生名字隐藏,因为我们是通过父类指针来调用的:
            首先进行名字查找的作用域是在父类,而不是子类,所以不存在名字隐藏的问题。
    */
    ani->eat();
}
  • 否则,将调用这个函数的静态类型的版本。例如:
#include <iostream>

class Animal {
    
    
public:
    void run() {
    
    
        std::cout << "animal run" << std::endl;
    }
};


class Dog : public Animal {
    
    
public:
    void run() {
    
    
        std::cout << "dog run" << std::endl;
    }
};

int main() {
    
    

    Animal* ani = new Dog();
    // 从静态类型作用域中进行名字查找,找到run,但是并没有virtual修饰:
        // 于是调用静态类型的版本
    ani->run(); // 打印aniaml run ,而不是 dog run
}

2. 重载

针对同一个作用域下,函数名字相同但是函数签名不同的函数,编译器会根据调用时的实参的个数、类型来自动匹配合适的函数。

3. 隐藏

名字隐藏的现象(定义):内层作用域的名字会导致外层作用域的同名对象不可见。
名字隐藏的本质原因是:名字查找先于类型检查。

注意,子类是父类的内层作用域。

典型的例子是:

  1. 父类中定义了一个函数void eat();
  2. 子类中也定义了一个函数void eat(std::string food);
  3. 那么子类在调用eat的时候,必须传入参数food,否则将编译不过。这是因为,编译先进行名字查找,查到了内层作用域中有eat,于是就无视了父类中的eat。然后进行类型检查,此时会发现类型不匹配。
#include <iostream>

class Animal {
    
    
public:
    void eat() {
    
    
        std::cout << "animal eat" << std::endl;
    }
};


class Dog : public Animal {
    
    
public:
    void eat(std::string food) {
    
    
        std::cout << "dog eat " << food << std::endl;
    }
    void print() {
    
    
        // this->eat(); // 编译不过,eat()被隐藏了
        Animal::eat(); // 可以编译过。
    }
};

int main() {
    
    

   Dog d;
//    d.eat(); // 错误,编译不过。父类eat被编译器无视了。
   d.eat("shi");
}

猜你喜欢

转载自blog.csdn.net/ustc_sse_shenzhang/article/details/127354963