当一个类声明了虚函数,这个虚函数性质具有继承的性质,在以后所有层次继承的类中,都是虚函数。
普通虚函数在子类中可以不被重写,但是纯虚函数必须被重写。
通过基类的指针访问子类,调用虚函数,调用的都是子类的虚函数。
并不是子类一定无法访问基类的虚函数,可以通过域名作用符访问。
普通虚函数在子类中可以不被重写,但是纯虚函数必须被重写,对此分别举出两个例子:
在C++中,虚函数和纯虚函数在继承关系中起着不同的作用。以下是两个例子,分别展示虚函数和纯虚函数在子类中的不同行为。
虚函数
cpp
#include <iostream>
class Base {
public:
virtual void show() {
std::cout << "Base class function" << std::endl;
}
};
class Derived : public Base {
public:
void show() {
std::cout << "Derived class function" << std::endl;
}
};
int main() {
Base* basePtr = new Base();
Base* derivedPtr = new Derived();
basePtr->show(); // 输出 "Base class function"
derivedPtr->show(); // 输出 "Derived class function"
delete basePtr;
delete derivedPtr;
return 0;
}
在这个例子中,Base
类有一个虚函数show()
。在Derived
类中,我们重写了show()
函数,所以当我们通过Derived
类的指针调用show()
时,将调用Derived
类的版本,而不是Base
类的版本。但是,如果我们不在Derived
类中重写show()
函数,那么编译器会报错,因为Base
类中的show()
函数是虚函数,必须在派生类中重写。
纯虚函数
cpp
#include <iostream>
class Base {
public:
virtual void show() = 0; // 纯虚函数
};
class Derived : public Base {
public:
void show() {
std::cout << "Derived class function" << std::endl;
}
};
int main() {
Base* derivedPtr = new Derived();
derivedPtr->show(); // 输出 "Derived class function"
delete derivedPtr;
return 0;
}
在这个例子中,Base
类有一个纯虚函数show()
。纯虚函数必须被重写,否则编译器会报错。在Derived
类中,我们重写了show()
函数,所以我们可以创建Derived
类的实例并通过Base
类的指针调用show()
。如果我们不在Derived
类中重写show()
函数,那么编译器将报错,因为Base
类中的show()
函数是纯虚函数,必须在派生类中重写。
注意,纯虚函数通常用于抽象基类,它们不能直接实例化,只能作为其他类的基类。
通过基类的指针访问子类,调用虚函数,调用的都是子类的虚函数。 并不是子类一定无法访问基类的虚函数,可以通过域名作用符访问。
确实,当通过基类的指针访问子类对象时,如果基类中有一个虚函数被子类重写,那么通过该基类指针调用这个虚函数时,会调用子类的版本。但如果子类想要调用基类的虚函数版本,它可以通过使用基类名作为前缀(也称为作用域解析运算符)来明确指定要调用的是基类中的函数。
下面是一个简单的例子来说明这个概念:
cpp
#include <iostream>
class Base {
public:
virtual void show() {
std::cout << "Base class function" << std::endl;
}
};
class Derived : public Base {
public:
void show() override {
std::cout << "Derived class function" << std::endl;
}
void showBase() {
Base::show(); // 调用基类中的show函数
}
};
int main() {
Derived d;
Base* basePtr = &d;
basePtr->show(); // 输出 "Derived class function"
d.showBase(); // 输出 "Base class function"
return 0;
}
在上面的例子中:
- 当我们通过基类指针
basePtr
调用show()
函数时,输出的是 "Derived class function",因为Derived
类重写了Base
类的show()
函数。 - 当我们在
Derived
类中调用showBase()
函数时,我们通过Base::show()
明确指定要调用的是基类中的show()
函数,所以输出的是 "Base class function"。
这个例子展示了如何通过基类的指针访问子类,调用子类重写的虚函数,同时也展示了如何在子类中直接调用基类的虚函数。