虛擬函式必須定義(純虛擬函式除外)
阿新 • • 發佈:2019-01-03
1. 虛擬函式的宣告和定義
具體關於虛擬函式的知識不做多講,我在定義一個抽象類時,忘了將一個虛擬函式宣告為 純虛擬函式,又沒有對其定義, 導致編譯報錯時報錯如下:
undefined reference to `vtable for Fibonacci'
錯誤提示的很明顯,就是無法生成虛擬函式表。
我們知道,虛擬函式表(地址)在定義了虛擬函式的類所例項化的物件記憶體中的第一個位置,也就是在例項化過程中生成了虛表。這個錯誤提示在stackflow中最常見的解答就是類中聲明瞭虛擬函式,卻沒有定義。
總結一下虛擬函式宣告和定義的規則如下:
類中的virtual函式,要麼設為純虛擬函式,要麼有定義,否則無法生成虛擬函式表。
虛擬函式的可以類外定義,但是必須加上類名,類外定義不需要加virtual
宣告為純虛擬函式,則類為抽象類,無法例項化,進一步強調,想要例項化有虛擬函式的類,必須對虛擬函式進行定義
基類定義為虛擬函式,則子類同名函式也為虛擬函式,無論是否有virtual關鍵字修飾(一般宣告時加virtual,便於閱讀)
凡是基類定義有虛擬函式,則基類需要定義虛解構函式(根據上一條法則,虛解構函式要麼有定義,要麼純虛,一般不設為純虛,可以定義空白)
虛擬函式通過虛表實現,虛表是類例項化時生成在物件中的(虛表地址),所以如果一個類能夠例項化,則其虛擬函式必須有定義,如果不想定義虛擬函式,只能宣告為純虛擬函式,留給子類定義。
基類為一個抽象類
// num_sequence.h
#ifndef _NUM_SEQUENCE
#define _NUM_SEQUENCE
#include <string>
#include <iostream>
using namespace std;
class num_sequence {
public:
num_sequence() {
cout << " create a num sequence" << endl;
}
virtual ~num_sequence() {
cout << "~num_sequence has been called" << endl;
}
virtual int elem(int pos) const= 0;
virtual const string what_am_i() const = 0;
static int max_elems(){
return _max_elems;
}
virtual ostream& print(ostream& = cout) const = 0;
protected:
virtual void gen_elems(int pos) const = 0; // const指標指向自認為const的一個物件, 這個物件不能通過const指標進行修改, 但可以通過其他方式進行修改
bool check_integrity(int pos) const{
if(pos <=0 || pos >_max_elems) {
cerr << "Invalid position: " << pos << endl;
return false;
}
return true;
}
const static int _max_elems = 1024; // 最大元素個數
};
#endif
子類不是抽象類,則必須實現基類的純虛擬函式
子類宣告:
// Fibonacci.h
#ifndef _FIBONACCI
#define _FIBONACCI
#include "num_sequence.h"
#include <vector>
using std::vector;
class Fibonacci : public num_sequence {
public:
Fibonacci(int len = 1, int beg_pos = 1): _length(len), _beg_pos(beg_pos){
cout << "create a Fibonacci sequence" << endl;
}
virtual int elem(int pos) const ; // 子類類中宣告virtual時, 應當和父類保持精確一致性
virtual ostream& print(ostream &os=cout) const;
virtual const string what_am_i() const{
cout << " I am Fibonacci sequence" << endl;
}
int length() const {
return _length;
}
int beg_pos() const{
return _beg_pos;
}
~Fibonacci() {
cout << "~Fibonacci has been called" << endl;
}
protected:
virtual void gen_elems(int pos) const;
int _length; // 長度
int _beg_pos; // 起始位置
static vector<unsigned int> _elems; // 元素容器
};
#endif
子類虛擬函式定義:
// Fibonacci.cpp
#include "Fibonacci.h"
vector<unsigned int> Fibonacci::_elems;
// 類外定義virtual函式時, 不需要virtual關鍵字
int Fibonacci::elem(int pos) const {
if(!check_integrity(pos)) // 檢查pos可用性
return 0;
if(pos > _elems.size() ) // 檢查當前元素個數是夠足夠, 當不足時自動生成
Fibonacci::gen_elems(pos); // 利用類作用域, 在編譯時指明呼叫函式
return _elems[pos - 1];
}
ostream& Fibonacci::print(ostream &os) const {
int elem_pos = _beg_pos - 1;
int end_pos = elem_pos + _length;
if(end_pos > _elems.size()) {
Fibonacci::gen_elems(end_pos);
}
while(elem_pos < end_pos) {
os << _elems[elem_pos] << "\t";
++elem_pos;
}
return os;
}
void Fibonacci::gen_elems(int pos) const {
if(_elems.empty()) {
_elems.push_back(1);
_elems.push_back(1);
}
if(_elems.size() <= pos) {
int ix = _elems.size();
int n_2 = _elems[ix-2];
int n_1 = _elems[ix-1];
for(; ix<=pos; ++ix){
int elem = n_2 + n_1;
_elems.push_back(elem);
n_2 = n_1;
n_1 = elem;
}
}
具體關於虛擬函式的知識不做多講,我在定義一個抽象類時,忘了將一個虛擬函式宣告為 純虛擬函式,又沒有對其定義, 導致編譯報錯時報錯如下:
undefined reference to `vtable for Fibonacci'
錯誤提示的很明顯,就是無法生成虛擬函式表。
我們知道,虛擬函式表(地址)在定義了虛擬函式的類所例項化的物件記憶體中的第一個位置,也就是在例項化過程中生成了虛表。這個錯誤提示在stackflow中最常見的解答就是類中聲明瞭虛擬函式,卻沒有定義。
總結一下虛擬函式宣告和定義的規則如下:
類中的virtual函式,要麼設為純虛擬函式,要麼有定義,否則無法生成虛擬函式表。
虛擬函式的可以類外定義,但是必須加上類名,類外定義不需要加virtual
宣告為純虛擬函式,則類為抽象類,無法例項化,進一步強調,想要例項化有虛擬函式的類,必須對虛擬函式進行定義
基類定義為虛擬函式,則子類同名函式也為虛擬函式,無論是否有virtual關鍵字修飾(一般宣告時加virtual,便於閱讀)
凡是基類定義有虛擬函式,則基類需要定義虛解構函式(根據上一條法則,虛解構函式要麼有定義,要麼純虛,一般不設為純虛,可以定義空白)
虛擬函式通過虛表實現,虛表是類例項化時生成在物件中的(虛表地址),所以如果一個類能夠例項化,則其虛擬函式必須有定義,如果不想定義虛擬函式,只能宣告為純虛擬函式,留給子類定義。
基類為一個抽象類
// num_sequence.h
#ifndef _NUM_SEQUENCE
#define _NUM_SEQUENCE
#include <string>
#include <iostream>
using namespace std;
class num_sequence {
public:
num_sequence() {
cout << " create a num sequence" << endl;
}
virtual ~num_sequence() {
cout << "~num_sequence has been called" << endl;
}
virtual int elem(int pos) const= 0;
virtual const string what_am_i() const = 0;
static int max_elems(){
return _max_elems;
}
virtual ostream& print(ostream& = cout) const = 0;
protected:
virtual void gen_elems(int pos) const = 0; // const指標指向自認為const的一個物件, 這個物件不能通過const指標進行修改, 但可以通過其他方式進行修改
bool check_integrity(int pos) const{
if(pos <=0 || pos >_max_elems) {
cerr << "Invalid position: " << pos << endl;
return false;
}
return true;
}
const static int _max_elems = 1024; // 最大元素個數
};
#endif
子類不是抽象類,則必須實現基類的純虛擬函式
子類宣告:
// Fibonacci.h
#ifndef _FIBONACCI
#define _FIBONACCI
#include "num_sequence.h"
#include <vector>
using std::vector;
class Fibonacci : public num_sequence {
public:
Fibonacci(int len = 1, int beg_pos = 1): _length(len), _beg_pos(beg_pos){
cout << "create a Fibonacci sequence" << endl;
}
virtual int elem(int pos) const ; // 子類類中宣告virtual時, 應當和父類保持精確一致性
virtual ostream& print(ostream &os=cout) const;
virtual const string what_am_i() const{
cout << " I am Fibonacci sequence" << endl;
}
int length() const {
return _length;
}
int beg_pos() const{
return _beg_pos;
}
~Fibonacci() {
cout << "~Fibonacci has been called" << endl;
}
protected:
virtual void gen_elems(int pos) const;
int _length; // 長度
int _beg_pos; // 起始位置
static vector<unsigned int> _elems; // 元素容器
};
#endif
子類虛擬函式定義:
// Fibonacci.cpp
#include "Fibonacci.h"
vector<unsigned int> Fibonacci::_elems;
// 類外定義virtual函式時, 不需要virtual關鍵字
int Fibonacci::elem(int pos) const {
if(!check_integrity(pos)) // 檢查pos可用性
return 0;
if(pos > _elems.size() ) // 檢查當前元素個數是夠足夠, 當不足時自動生成
Fibonacci::gen_elems(pos); // 利用類作用域, 在編譯時指明呼叫函式
return _elems[pos - 1];
}
ostream& Fibonacci::print(ostream &os) const {
int elem_pos = _beg_pos - 1;
int end_pos = elem_pos + _length;
if(end_pos > _elems.size()) {
Fibonacci::gen_elems(end_pos);
}
while(elem_pos < end_pos) {
os << _elems[elem_pos] << "\t";
++elem_pos;
}
return os;
}
void Fibonacci::gen_elems(int pos) const {
if(_elems.empty()) {
_elems.push_back(1);
_elems.push_back(1);
}
if(_elems.size() <= pos) {
int ix = _elems.size();
int n_2 = _elems[ix-2];
int n_1 = _elems[ix-1];
for(; ix<=pos; ++ix){
int elem = n_2 + n_1;
_elems.push_back(elem);
n_2 = n_1;
n_1 = elem;
}
}
}
http://blog.csdn.net/gvfdbdf/article/details/51954819