2017-04-05 40 views
-4

为什么下面的C++代码给出了下面提到的错误?为什么这不是用C++编写递归数据结构的惯用方式?这种编写C++的方式是否存在根本性错误?由编译器给出下面的C++程序有什么问题?

#include<iostream> 
using namespace std; 


class tree{ 
public: 
    virtual void inorder() {}; 
}; 

class emp_tree: public tree{ 
public: 
    void inorder(){ 
    } 
}; 

class non_emp_tree: public tree{ 
public: 
    tree left, right; 
    int val; 
    non_emp_tree(int v, tree l, tree r): val(v), left(l), right(r) {}; 
    void inorder(){ 
     left.inorder(); 
     cout<<" "<<val<<" "; 
     right.inorder(); 
    } 
}; 




int main() { 
    tree leaf1 = non_emp_tree(1, emp_tree(), emp_tree()); 
    tree leaf2 = non_emp_tree(3, emp_tree(), emp_tree()); 
    tree root = non_emp_tree(2, leaf1, leaf2); 
    root.inorder(); 
    return 0; 
} 

错误:(我无法理解的是大多数)

/tmp/ccAjhirw.o: In function `main': 
b_t.cpp:(.text+0x16e): undefined reference to `tree::inorder()' 
/tmp/ccAjhirw.o: In function `tree::tree()': 
b_t.cpp:(.text._ZN4treeC2Ev[_ZN4treeC5Ev]+0x9): undefined reference to `vtable for tree' 
/tmp/ccAjhirw.o: In function `tree::tree(tree const&)': 
b_t.cpp:(.text._ZN4treeC2ERKS_[_ZN4treeC5ERKS_]+0xd): undefined reference to `vtable for tree' 
/tmp/ccAjhirw.o: In function `non_emp_tree::inorder()': 
b_t.cpp:(.text._ZN12non_emp_tree7inorderEv[_ZN12non_emp_tree7inorderEv]+0x19): undefined reference to `tree::inorder()' 
b_t.cpp:(.text._ZN12non_emp_tree7inorderEv[_ZN12non_emp_tree7inorderEv]+0x56): undefined reference to `tree::inorder()' 
/tmp/ccAjhirw.o: In function `tree::tree(tree&&)': 
b_t.cpp:(.text._ZN4treeC2EOS_[_ZN4treeC5EOS_]+0xd): undefined reference to `vtable for tree' 
/tmp/ccAjhirw.o:(.rodata._ZTI12non_emp_tree[_ZTI12non_emp_tree]+0x10): undefined reference to `typeinfo for tree' 
/tmp/ccAjhirw.o:(.rodata._ZTI8emp_tree[_ZTI8emp_tree]+0x10): undefined reference to `typeinfo for tree' 
collect2: error: ld returned 1 exit status 

编辑:我改变​​到virtual void inorder() {}即空的实现。但我仍然没有得到期望的输出,看起来root,leaf1和leaf2都调用树的顺序而不是它们各自的inorders。

+0

可能重复[什么是未定义的引用/无法解析的外部符号错误,以及如何解决它?](http://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved- external-symbol-error-and-how-do-i-fix) – Rakete1111

+1

@ Rakete1111我不相信它是。或者,更确切地说,我认为OP的问题与该问题中描述的问题是垂直的。 – Xirema

+1

@Xirema如果在常见问题中描述了问题,那为什么它不是重复的? – Rakete1111

回答

3

您从未实施过​​。

class tree{ 
public: 
    virtual void inorder(); 
}; 

在这里你声称有这样的功能 - 它的实现在哪里?

此外,这没有任何意义:

tree leaf1 = non_emp_tree(1, emp_tree(), emp_tree()); 

你设置tree的价值等于non_emp_tree的价值。这当然不会做任何有用的事情。

+3

我希望从downvoter的解释。 –

+3

我没有投票,但是你的回答是不正确的。代码正在切片,而不是使用虚拟调度。请注意,没有指针。 OPs代码看起来像试图使用虚拟呼叫,但忘记了它们需要成为指针。 –

+0

@RichardCritten他的回答是代码问题之一。 – Eddge

1

virtual void inorder(){}应该在你的树类,你缺失{}

+1

无论是“{}”还是“= 0;”都会修复它;考虑到他可能试图用'tree'作为抽象基类实现多态性,后者会更有意义。 – Quietust

+0

是你说得对。感谢提及 –

+0

@静谧如果他用'= 0定义它;'他会有一个新的编译器错误,因为孩子不会重写该函数,为了使用'= 0;'他会需要在inorder函数中虚拟标记子类。他也无法做出树类的实例。所以他的主要3个变量会出错。 – Eddge

0

类“树”的“序”方法未实现,所以你打电话时,得到一个未定义的参照此方法。

1

你大概试图做的是使用多态性。但是,为此,您必须使用引用或指针,而不是基本本身。即

#include<iostream> 
#include<memory> 

struct tree 
{ 
    virtual void inorder() = 0; // abstract: cannot be called 
    virtual ~tree() {} 
}; 

struct emp_tree : tree 
{ 
    void inorder() override 
    {} 
}; 

struct non_emp_tree : tree 
{ 
    std::unique_ptr<tree> left,right; 
    int val; 
    non_emp_tree(int v, tree*l, tree*r) 
    : left(l), right(r), val(v) {} 
    void inorder() override 
    { 
    left->inorder(); 
    std::cout<<" "<<val<<" "; 
    right->inorder(); 
    } 
}; 

int main() { 
    auto leaf1 = new non_emp_tree(1, new emp_tree, new emp_tree); 
    auto leaf2 = new non_emp_tree(3, new emp_tree, new emp_tree); 
    auto root = new non_emp_tree(2, leaf1, leaf2); 
    root->inorder(); 
} 

与铛编译,产生1 2 3。第一

+0

上面的代码不会编译,虽然'虚拟void inorder(){};'编译和行为很好。你可以解释吗? –

+0

@Walter您需要将默认的'virtual'析构函数添加到'tree',否则清理将无法正常工作。 – Xirema

+0

代码**确实**编译,我做到了。你可能错过了相关的系统头文件。我将在编辑中添加它们。 – Walter

1

第一件事,如果​​意味着是一个抽象方法,你需要正确地宣布它是这样:

class tree{ 
public: 
    virtual void inorder() = 0; 
}; 

然而,这很快会导致很多其他问题,因为你正在将你的物体左右分割!

tree leaf1 = non_emp_tree(1, emp_tree(), emp_tree()); 

此代码不可能有你想要的效果。 non_emp_tree包含一个tree对象没有空间存储的成员变量。即使它确实如此,你也不能保证对象会按照你的期望行事。 inorderleaf1的调用将尝试调用​​而不是non_emp_tree::inorder,因为程序无法知道您打算在此处存储子类。

解决这个问题的方法是为所有的tree对象使用指针。

#include<iostream> 
#include<memory> 

class tree{ 
public: 
    virtual void inorder() = 0; 
    virtual ~tree() = default; 
}; 

class emp_tree: public tree{ 
public: 
    void inorder(){ 
    } 
}; 

class non_emp_tree: public tree{ 
public: 
    std::unique_ptr<tree> left, right; 
    int val; 
    non_emp_tree(int v, tree *l, tree *r): val(v), left(l), right(r) {}; 
    void inorder(){ 
     if(left) left->inorder(); 
     std::cout<<" "<<val<<" "; 
     if(right) right->inorder(); 
    } 
}; 

int main() { 
    std::unique_ptr<tree> leaf1 = std::make_unique<non_emp_tree>(1, new emp_tree, new emp_tree); 
    std::unique_ptr<tree> leaf2 = std::make_unique<non_emp_tree>(3, new emp_tree, new emp_tree); 
    std::unique_ptr<tree> root = std::make_unique<non_emp_tree>(2, leaf1.release(), leaf2.release()); 
    root->inorder(); 
    return 0; 
} 

更好的实现这个代码将避免裸new在所有任何用途,但这需要你的代码的一些显著重构。