面试题:什么是虚函数?

简介: 面试题:什么是虚函数?

面试题:什么是虚函数

在 C++ 中,虚函数是一种特殊的成员函数,它允许在基类中使用 virtual 关键字声明,在派生类中进行重写,并且可以通过基类指针或引用调用派生类的成员函数。虚函数实现了 C++ 的多态特性,提高了程序的灵活性、可移植性和可维护性。

虚函数的声明和定义

虚函数的声明需要在函数前面加上 virtual 关键字,例如:

class Animal {
public:
    virtual void speak();
};
class Dog : public Animal {
public:
    virtual void speak();
};

上面的代码中,Animal 类有一个虚函数 speak(),Dog 类继承自 Animal 并重写了 speak() 函数。

虚函数的定义也需要在函数名前面加上 virtual 关键字,并且可以带有默认实现,例如:

void Animal::speak() {
    std::cout << "I am an animal." << std::endl;
}
void Dog::speak() {
    std::cout << "I am a dog." << std::endl;
}

上面的代码中,Animal 和 Dog 类分别实现了 speak() 函数的默认行为和重写行为。

调用虚函数

虚函数通过基类指针或引用来调用派生类的成员函数。例如:

int main() {
    Animal ani;
    Dog dog;
    Animal *p = &ani;
    p->speak(); // 输出: I am an animal.
    p = &dog;
    p->speak(); // 输出: I am a dog.
    return 0;
}

上面的代码中,通过基类指针 p 分别调用了基类和派生类的 speak() 函数,实现了虚函数多态性的效果。

需要注意的是,虚函数只能针对具有公共子类型的对象使用,并且建议将虚函数声明为 public。否则在调用时会出现编译器错误或者运行时的崩溃。

虚析构函数

还有一个非常重要的内容:如果你在具有派生类的基类析构函数中不是将析构函数声明为虚拟,则不会删除具有派生类对象的基类指针的派生类对象。

例如:

class Animal {
public:
    virtual void speak();
    ~Animal();
};
Animal::~Animal() {
    cout << "Calling Animal destructor" << endl;
}
class Dog : public Animal {
public:
    void speak();
    ~Dog();
};
Dog::~Dog() {
    cout << "Calling Dog destructor" << endl;
}
int main() {
    Animal *p = new Dog;
    delete p;
    p = nullptr;
    return 0;
}

输出结果是:

Calling Dog destructor
Calling Animal destructor

可以看到,在这种情况下,派生类的析构函数没有被调用。此时,Animal 的析构函数不是虚函数,所以当使用的时候调用是 Animal 的析构函数。因此,如果您计划通过一个基类指针删除派生的对象,请将基类的析构函数声明为虚拟的。

总结

虚函数是 C++ 中实现多态的重要机制之一,它允许在基类中声明函数为虚拟函数,在派生类中进行重写,并且可以通过基类指针或引用调用派生类的成员函数。虚函数提高了程序的灵活性、可移植性和可维护性,但也需要注意继承层次的公共子类型、虚析构函数等问题。

相关文章
|
9月前
|
C++
面试题:基类的析构函数为何要声明为虚函数?
面试题:基类的析构函数为何要声明为虚函数?
70 0
|
测试技术
软件测试面试题:请讲一讲析构函数和虚函数的用法和作用?
软件测试面试题:请讲一讲析构函数和虚函数的用法和作用?
111 0
|
存储 缓存 Java
【阿里面试】C++多态和虚函数
2.1 现在假设有一个编译好的C++程序,编译没有错误,但是运行时报错,报错如下:你正在调用一个纯虚函数(Pure virtual function call error),请问导致这个错误的原因可能是什么?
332 0
【阿里面试】C++多态和虚函数
|
安全 C++
【C++面试】虚函数和纯虚函数
因为写代码时不能在一开始就确定被调用的是基类的函数,还是哪个派生类的成员函数,所以C++通过虚函数实现多态,即在基类中用virtual声明,父类可以引用子类对象(如Human* phuman1 = new Men;父类类型指针phuman指向子类对象),子类成员函数可以重写父类方法(函数)。
201 0
【C++面试】虚函数和纯虚函数
|
6月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
3月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
3月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?