C++ 中 dynamic_cast 的问题

issues with dynamic_cast in C++

我正在用 C++ 实现非均匀链表(.cpp 和 .h 文件在下面)。

使用英特尔编译器在 Linux 中编译:icpc test.cpp List.cpp -o test 会出现很多错误(见下文)。看来问题出在 List.cpp 中包含 dynamic_cast 的行。语法在我看来是正确的。有人可以帮我查明问题吗?

/tmp/icpcIuHg7X.o: In function `InhomList::getPrev(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
List.cpp:(.text+0x25): undefined reference to `typeinfo for BaseEl'
/tmp/icpcIuHg7X.o: In function `InhomList::getPos(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
List.cpp:(.text+0x134): undefined reference to `typeinfo for BaseEl'
/tmp/icpcIuHg7X.o: In function `InhomList::insertAfter(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Cell*)':
List.cpp:(.text+0x267): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x346): undefined reference to `vtable for BaseEl'
/tmp/icpcIuHg7X.o: In function `InhomList::insertAfter(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Cell*)':
List.cpp:(.text+0x43b): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x4c8): undefined reference to `vtable for DerivedEl'
List.cpp:(.text+0x59c): undefined reference to `BaseEl::~BaseEl()'
List.cpp:(.text+0x5c9): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x659): undefined reference to `vtable for DerivedEl'
List.cpp:(.text+0x71c): undefined reference to `BaseEl::~BaseEl()'
/tmp/icpcIuHg7X.o: In function `InhomList::erasePos(Cell*)':
List.cpp:(.text+0x756): undefined reference to `typeinfo for BaseEl'
/tmp/icpcIuHg7X.o: In function `InhomList::InhomList(InhomList const&)':
List.cpp:(.text+0x8c3): undefined reference to `typeinfo for DerivedEl'
List.cpp:(.text+0x8d5): undefined reference to `typeinfo for DerivedEl'
List.cpp:(.text+0x915): undefined reference to `typeinfo for DerivedEl'
List.cpp:(.text+0x97c): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0xa61): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0xaf4): undefined reference to `vtable for DerivedEl'
List.cpp:(.text+0xb7c): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0xc97): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0xd4d): undefined reference to `BaseEl::~BaseEl()'
List.cpp:(.text+0xdad): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0xe4a): undefined reference to `vtable for DerivedEl'
List.cpp:(.text+0xf1c): undefined reference to `BaseEl::~BaseEl()'
List.cpp:(.text+0xf7b): undefined reference to `vtable for BaseEl'
/tmp/icpcIuHg7X.o: In function `InhomList::InhomList(InhomList const&)':
List.cpp:(.text+0x1063): undefined reference to `typeinfo for DerivedEl'
List.cpp:(.text+0x1075): undefined reference to `typeinfo for DerivedEl'
List.cpp:(.text+0x10b5): undefined reference to `typeinfo for DerivedEl'
List.cpp:(.text+0x111c): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0x1201): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x1294): undefined reference to `vtable for DerivedEl'
List.cpp:(.text+0x131c): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0x1437): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x14ed): undefined reference to `BaseEl::~BaseEl()'
List.cpp:(.text+0x154d): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x15ea): undefined reference to `vtable for DerivedEl'
List.cpp:(.text+0x16bc): undefined reference to `BaseEl::~BaseEl()'
List.cpp:(.text+0x171b): undefined reference to `vtable for BaseEl'
/tmp/icpcIuHg7X.o: In function `InhomList::operator=(InhomList const&)':
List.cpp:(.text+0x18eb): undefined reference to `typeinfo for DerivedEl'
List.cpp:(.text+0x18fd): undefined reference to `typeinfo for DerivedEl'
List.cpp:(.text+0x193d): undefined reference to `typeinfo for DerivedEl'
List.cpp:(.text+0x19a4): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0x1a89): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x1b1c): undefined reference to `vtable for DerivedEl'
List.cpp:(.text+0x1ba4): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0x1cbf): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x1d79): undefined reference to `BaseEl::~BaseEl()'
List.cpp:(.text+0x1dd9): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x1e76): undefined reference to `vtable for DerivedEl'
List.cpp:(.text+0x1f48): undefined reference to `BaseEl::~BaseEl()'
List.cpp:(.text+0x1fa7): undefined reference to `vtable for BaseEl'
/tmp/icpcIuHg7X.o: In function `InhomList::insert(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
List.cpp:(.text+0x2086): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0x2160): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x223f): undefined reference to `vtable for BaseEl'
/tmp/icpcIuHg7X.o: In function `InhomList::insert(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
List.cpp:(.text+0x231b): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0x23f7): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x2488): undefined reference to `vtable for DerivedEl'
List.cpp:(.text+0x2560): undefined reference to `BaseEl::~BaseEl()'
List.cpp:(.text+0x258e): undefined reference to `vtable for BaseEl'
List.cpp:(.text+0x261f): undefined reference to `vtable for DerivedEl'
List.cpp:(.text+0x26e6): undefined reference to `BaseEl::~BaseEl()'
/tmp/icpcIuHg7X.o: In function `InhomList::erase(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
List.cpp:(.text+0x2716): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0x2789): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0x279f): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0x27e6): undefined reference to `typeinfo for BaseEl'
List.cpp:(.text+0x27f8): undefined reference to `typeinfo for BaseEl'
/tmp/icpcIuHg7X.o:List.cpp:(.text+0x281c): more undefined references to `typeinfo for BaseEl' follow

test.cpp: 程序

#include "List.h"
#include <typeinfo>

int main() {


    return 0;
}

cell.h:定义 classes Cell、BaseEl 和 DerivedEl

    // --------------------------------------------------------
    #ifndef _CELL_
    #define _CELL_
    #include <string>
    #include <iostream>
    using namespace std;

    // Abstract class
    class Cell {
    private:
        Cell *next;
    protected:
        Cell(Cell *suc = NULL) :
                next(suc) {
            ;
        }
    public:
        virtual ~Cell() {
        }

        // Access methods:
        Cell* getNext(void) const {
            return next;
        }
        void setNext(Cell *suc) {
            next = suc;
        }

        virtual void display() const = 0;
    };

    class BaseEl: public Cell {
    private:
        string name;
    public:
        BaseEl(Cell *suc = NULL, const string &s = "") :
                Cell(suc), name(s) {
            ;
        }
        ~BaseEl();

        // Access methods:
        const string& getName(void) const {
            return name;
        }
        void setName(const string &s) {
            name = s;
        }

        void display() const {
            cout << endl << "------------------------------" << endl << "Name: "
                    << name << endl;
        }
    };

    class DerivedEl: public BaseEl {
    private:
        string rem;
    public:
        DerivedEl(Cell *suc = NULL, const string &s = "", const string &b = "") :
                BaseEl(suc, s), rem(b) {
            ;
        }
        ~DerivedEl();

        // Access methods:
        const string& getRem(void) {
            return rem;
        }
        void setRem(const string &s) {
            rem = s;
        }

        void display() const {
            BaseEl::display();
            cout << "Remark: " << rem << endl;
        }
    };

    #endif

List.h: 定义 class InhomList.h

// --------------------------------------------------------
#ifndef _LIST_
#define _LIST_
#include "cell.h"
using namespace std;

class InhomList {
private:
    Cell *first;
protected:
    Cell* getPrev(const string &s);
    Cell* getPos(const string &s);
    void insertAfter(const string &s, Cell *prev);
    void insertAfter(const string &s, const string &b, Cell *prev);
    void erasePos(Cell *pos);
public:
    InhomList() {
        first = NULL;
    }
    InhomList(const InhomList &src);
    ~InhomList();
    InhomList& operator=(const InhomList &src);
    void insert(const string &n);
    void insert(const string &n, const string &b);
    void erase(const string &n);
    void displayAll() const;
};

#endif

List.cpp:List.h

的方法
#include "List.h"
#include <typeinfo>

// Copy constructor:
InhomList::InhomList(const InhomList &src) {
    // Append the elements from src to the empty list.
    first = NULL;
    Cell *pEl = src.first;
    for (; pEl != NULL; pEl = pEl->getNext()) {

        if (typeid(*pEl) == typeid(DerivedEl)) {
            insert(dynamic_cast<DerivedEl*>(pEl)->getName(),
                    dynamic_cast<DerivedEl*>(pEl)->getRem());
        } else
            insert(dynamic_cast<BaseEl*>(pEl)->getName());

    }
}

// Destructor:
InhomList::~InhomList() {
    Cell *pEl = first, *next = NULL;
    while (pEl != NULL) {
        next = pEl->getNext();
        delete pEl;
        pEl = next;
    }
}

// Assignment:
InhomList& InhomList::operator=(const InhomList &src) {
    // To free storage for all elements:
    Cell *pEl = first, *next = NULL;
    while (pEl != NULL) {
        next = pEl->getNext();
        delete pEl;
        pEl = next;
    }
    first = NULL; // Empty list
    pEl = src.first; // Copy the elements from src to the empty list
    for (; pEl != NULL; pEl = pEl->getNext())
        if (typeid(*pEl) == typeid(DerivedEl))
            insert(dynamic_cast<DerivedEl*>(pEl)->getName(),
                    dynamic_cast<DerivedEl*>(pEl)->getRem());
        else
            insert(dynamic_cast<BaseEl*>(pEl)->getName());
    return *this;
}

void InhomList::insert(const string &n) {
    Cell *pEl = getPrev(n);
    insertAfter(n, pEl);
}

void InhomList::insert(const string &n, const string &b) {
    Cell *pEl = getPrev(n);
    insertAfter(n, b, pEl);
}

void InhomList::erase(const string &n) {
    erasePos(getPos(n));
}

void InhomList::displayAll() const {
    Cell *pEl = first;
    while (pEl != NULL) {
        pEl->display();
        pEl = pEl->getNext();
    }
}

Cell* InhomList::getPrev(const string &n) {
    Cell *pEl = first, *prev = NULL;
    while (pEl != NULL) {
        if (n > dynamic_cast<BaseEl*>(pEl)->getName()) {
            prev = pEl;
            pEl = pEl->getNext();
        } else
            return prev;
    }
    return prev;
}

Cell* InhomList::getPos(const string &n) {
    Cell *pEl = first;
    while (pEl != NULL && (n != dynamic_cast<BaseEl*>(pEl)->getName()))
        pEl = pEl->getNext();
    if (pEl != NULL && n == dynamic_cast<BaseEl*>(pEl)->getName())
        return pEl;
    else
        return NULL;
}

void InhomList::insertAfter(const string &s, Cell *prev) {
    if (prev == NULL) // Insert at the beginning:
        first = new BaseEl(first, s);
    else // In the middle or at the end:
    {
        Cell *p = new BaseEl(prev->getNext(), s);
        prev->setNext(p);
    }
}

void InhomList::insertAfter(const string &s, const string &b, Cell *prev) {
    if (prev == NULL) // Insert at the beginning:
        first = new DerivedEl(first, s, b);
    else // In the middle or at the end:
    {
        Cell *p = new DerivedEl(prev->getNext(), s, b);
        prev->setNext(p);
    }
}

void InhomList::erasePos(Cell *pos) {
    Cell *temp;
    if (pos != NULL)
        if (pos == first) // Delete the first element
                {
            temp = first;
            first = first->getNext();
            delete temp;
        } else // Delete from the middle or at the end
        { // Get the predecessor
            temp = getPrev(dynamic_cast<BaseEl*>(pos)->getName());
            if (temp != NULL) // and bend pointer.
                temp->setNext(pos->getNext());
            delete pos;
        }
}

您可以从修复此错误开始:

undefined reference to `BaseEl::~BaseEl()'

发生此错误是因为您声明了 BaseEl::~BaseEl():

~BaseEl();

但是你没有提供定义。您可以将定义提供为 ~BaseEl() override {}~BaseEl() override = default;,或者在 cell.cpp 或类似文件中将其定义为外联。

同样你需要确保给DerivedEl::~DerivedEl()一个定义。

如果我没记错的话,提供这些定义将消除 "undefined reference to vtable" 和 "undefined reference to typeinfo" 错误。有关可能的解释,请参阅 here