C++ 中虛擬函式和純虛擬函式的區別
本文將介紹 C++ 中虛擬函式和純虛擬函式的區別。
C++ 中的虛擬函式及其特性
虛擬函式與多型性的概念密切相關。在 C++ 中,我們可以在連結層次結構中組織不同的類,其中它們可能共享一些資料成員並具有作為介面公開的相同成員函式。
通常,從其他類繼承部分程式碼的類稱為派生類,而繼承自其他類的類稱為基類。請注意,有時這些術語可以與父子或超類-子類名稱互換使用。可以在派生類中覆蓋的函式稱為虛擬函式,它們用關鍵字 virtual
宣告。虛擬函式在給定的類層次結構中具有相同的名稱,每個派生類都可以實現自己的函式定義。
如果函式未被覆蓋,則派生類物件呼叫基類中定義的函式。下面的示例程式通過在 Engineer
和 Employee
類中定義 print
函式來演示虛擬函式的基本用法。然後我們可以實現一些任意函式 Func
,它接受對 Employee
的引用,並在體內呼叫 print
函式。
現在,Func
實現可能會多次更改,但它始終會根據作為引數傳遞的物件呼叫相應的 print
函式。我們可以在 Employee
類層次結構中新增多個派生類。它們中的每一個都可能/可能不實現 print
函式,但 Func
函式將接受它們的例項並呼叫正確的虛擬函式。
#include <iostream>
#include <string>
using std::cout; using std::endl;
using std::string; using std::cin;
class Employee {
public:
Employee(string fn, string ln) : first_name(std::move(fn)),
last_name(std::move(ln)){}
virtual void print() {
cout << "name: " << first_name << "\n"
<< "last name: " << last_name << "\n";
};
protected:
string first_name, last_name;
};
class Engineer : public Employee {
public:
Engineer(string fn, string ln, string sp) : Employee(std::move(fn), std::move(ln)),
specialization(std::move(sp)) {}
void print() override {
Employee::print();
cout << "specialization: " << specialization << "\n";
}
private:
string specialization;
};
void Func(Employee &em) {
em.print();
}
int main() {
Employee em1("Jim", "Jiao");
Engineer eng1("Jin", "Baker", "Aerospace Engineering");
Func(em1);
cout << "\n";
Func(eng1);
return EXIT_SUCCESS;
}
輸出:
name: Jim
last name: Jiao
name: Jin
last name: Baker
specialization: Aerospace Engineering
C++ 中的純虛擬函式和抽象型別
另一方面,我們有純虛擬函式的概念,它的宣告類似於常規虛擬函式,幷包含符號 = 0;
在宣告的末尾。這些函式本質上在基類中沒有定義,它們首先在基類中宣告。因此,它們很可能在派生類中定義。
包含純虛擬函式的類稱為抽象類,它們通常用於指定派生類的介面。注意抽象類不能直接例項化。
下一個程式碼片段使用抽象基類 Shape
實現 Triangle
和 Rectangle
類。在這種情況下,我們在兩個派生類中定義了 printArea
純虛擬函式。有時,派生類可能不會定義繼承的純虛擬函式,使其成為給定類層次結構中的另一個抽象類。派生類可以繼承多個純虛擬函式。如果它甚至沒有定義其中之一,則將抽象分類應用於該類。
#include <iostream>
#include <string>
#include <vector>
using std::cout; using std::endl;
using std::string; using std::vector;
class Shape {
public:
virtual void printArea() = 0;
};
class Triangle : public Shape {
public:
Triangle(double b, double h) : base(b), height(h) {}
void printArea() override {
cout << (base * height) / 2.0;
}
private:
double base;
double height;
};
class Rectangle : public Shape {
public:
Rectangle(double i1, double i2) : edges({i1, i2}) {}
void printArea() override {
cout << edges[0] * edges[1];
}
private:
vector<double> edges;
};
int main() {
Triangle t1(3, 5);
t1.printArea();
cout << "\n";
Rectangle r1(3, 5);
r1.printArea();
cout << "\n";
return EXIT_SUCCESS;
}
輸出:
7.5
15
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn