codeblocks:编译问题 undefined reference to vtable for...

一个严重的问题,在codeblocks用C++编程中出现 undefined reference to vtable for…的问题,昨天就遇到了,今天通过查资料才解决,主要涉及到类中的虚函数实现的问题。
在这里插入图片描述
相信大家都有习惯,编程时,写几个函数就编译一下,否则全写好再编译的话会,会导致一堆报错让人头疼。但正是这个习惯让我碰到了 undefined reference to ‘vtable for …’ 的问题。
先抛出结论:写类函数实现的时候一定要先写虚函数的实现,不然就会出现上面的问题。
下面写下问题发现过程:
我在练习类继承的时候,先写好了基类和派生类框架,然后在另一个文件中写函数实现

//brass.h
//brass account 基类
class Brass
{
    std::string fullname;
    long acctNum;
    double balance;
public:
    Brass(const std::string &s = "nobody", long an = -1, double bal = 0.0);
    void Deposit(double amt);
    virtual void Withdraw(double amt);//虚函数
    double Balance()const;
    virtual void ViewAccount()const;//虚函数
    virtual ~Brass(){}//虚函数,内联函数
};
//brass account plus 派生类
class BrassPlus : public Brass//对于解决这个问题不重要,可以不看
{
    double maxloan;
    double rate;
    double owesBank;
public:
    BrassPlus(const std::string &s = "nobody", long an = -1, double bal = 0.0,
              double ml = 500, double r = 0.11125);
    BrassPlus(const Brass &ba, double ml = 500, double r = 0.11125);
    virtual void ViewAccount()const;
    virtual void Withdraw(double amt);
    void ResetMax(double m){maxloan = m;}
    void ResetRate(double r){rate = r;}
    void ResetOwes(){owesBank = 0;}
};

下面是类实现的一部分

Brass::Brass(const std::string &s, long an, double bal)
{
    fullname = s;
    acctNum = an;
    balance = bal;
}
void Brass::Deposit(double amt)
{
    if (amt < 0)
        std::cout << "Negative deposit not allowed; " << "deposit is cancelled.\n";
    else
        balance += amt;
}//只实现了基类的构造函数和一个存钱函数

如果只写到这里进行编译会出上面的错误,问题在于**写继承类的时候,必须将基类中的虚函数实现写好才可以写继承类。**我将基类的虚函数全部写好如下(并没有写派生类中的实现):

#include <iostream>
#include <string>
#include "brass.h"
//    std::string fullname;
//    long acctNum;
//    double balance;//类中的三个内容
typedef std::ios_base::fmtflags format;
typedef std::streamsize precis;
format setFormat();
void restore(format f, precis p);//为了更改输出格式方便

Brass::Brass(const std::string &s, long an, double bal)
{
    fullname = s;
    acctNum = an;
    balance = bal;
}
void Brass::Deposit(double amt)
{
    if (amt < 0)
        std::cout << "Negative deposit not allowed; " << "deposit is cancelled.\n";
    else
        balance += amt;
}
void Brass::Withdraw(double amt)//基类虚函数
{
    format initialState = setFormat();
    precis prec = std::cout.precision(2);

    if (amt < 0)
        std::cout << "Withdrawal amount must be positive; "
            << "Withdrawal canceled.\n";
    else if (amt <= balance)
        balance -= amt;
    else
        std::cout << "Withdrawal amount of $" << amt
            << " exceeds your balance.\n"
            << "Withdrawal canceled.\n";
    restore(initialState, prec);
}
double Brass::Balance()const
{
    return balance;
}
void Brass::ViewAccount()const//基类虚函数
{
    format initialState = setFormat();
    precis prec = std::cout.precision(2);
    std::cout << "Client: " << fullname << std::endl;
    std::cout << "Account Number: " << acctNum << std::endl;
    std::cout << "Balacce: $" << balance << std::endl;
    restore(initialState, prec); //restore original format
}



format setFormat()//重点在于两个虚函数写好了,这些不懂的话没关系,以后就懂了
{
    return std::cout.setf(std::ios_base::fixed,
                          std::ios_base::floatfield);
}
void restore(format f, precis p)
{
    std::cout.setf(f, std::ios_base::floatfield);
    std::cout.precision(p);
}

在此时进行编译就已经通过了,问题得到解决。但是深层次的原因还是不很理解。
我的简单理解是问题出在最开始的.h文件,也就是写类框架的时候。一般正常思路是写派生类的时候,基类的一切都已经写好了,派生类总不能继承于一个半吊子基类。然后发现我错了,关键在于类中的虚函数。
类中的虚函数是个复杂的东西。不仅仅是基类,写派生类的时候也要写完派生类的虚函数实现再编译才会通过,应该涉及到动态联编的原理,可查阅相关资料。
所以以后练习的时候要注意,先写虚函数,以上代码出自c++primer plus 程序清单13.7、8。

猜你喜欢

转载自blog.csdn.net/weixin_43233774/article/details/86350362