【问题标题】:C++: Why Position constructor are called when the argument type does not match?C++:为什么当参数类型不匹配时调用位置构造函数?
【发布时间】:2022-11-11 05:21:50
【问题描述】:

这会有点冗长,但无论如何我尽力使用代码来简化它。
我正在构建一棵二叉树,但注意到一些奇怪的东西。

  1. linked_binary_tree.h
    #ifndef LINKED_BINARY_TREE_H
    #define LINKED_BINARY_TREE_H
    
    #include <iostream>
    #include <list>
    using namespace std;
    
    typedef int Elem; 
    
    class LinkedBinaryTree {
    
    protected:
        
        struct Node {
            Elem ele;
            Node *par;
            Node *left;
            Node *right;
            Node(): ele(), par(NULL), left(NULL), right(NULL) {}
        };
    
    public:
    
        class Position {
            friend LinkedBinaryTree;
            private:
                Node *v;
            public:
                Position(Node *_v=NULL): v(_v) { cout << "Position constr" << endl;}
                Elem &operator*() const {
                    return v->ele;
                }
                Position left() const {
                    return Position (v->left);
                }
                Position right() const {
                    return Position (v->right);
                }
                Position parent() const {
                    return Position(v->par);
                }
                bool isRoot() const {
                    return v->par==NULL;
                }
                bool isExternal() const {
                    return v->left==NULL && v->right==NULL;
                }
        };
    
        typedef list<Position>  PositionList;
    
        LinkedBinaryTree();
        int size() const;
        bool empty() const;
        Position root() const;
        PositionList positions(int trv) const;
        void addRoot();
        void expandExternal(const Position &p);
        Position removeAboveExternal(const Position &p);
    
    protected:
        void preorder(Node *v, PositionList &pl) const;
        void postorder(Node *v, PositionList &pl) const;
        void inorder(Node *v, PositionList &pl) const;
    
    private:
        Node * _root;
        int n;
    
    };
    
    #endif
    
    
    1. linked_binary_tree.cc
    #include <iostream>
    #include <list>
    #include "linked_binary_tree.h"
    using namespace std;
    
    LinkedBinaryTree::LinkedBinaryTree(): _root(NULL), n(0) {}
    
    int LinkedBinaryTree::size() const {
        return n;
    }
    
    bool LinkedBinaryTree::empty() const {
        return size()==0;
    }
    
    LinkedBinaryTree::Position LinkedBinaryTree::root() const {
        cout << "LinkedBinaryTree::root()" << endl;
        return Position(_root);
    }
    
    void LinkedBinaryTree::addRoot() {
        _root=new Node;
        n=1;
        _root->ele=n;
    }
    
    void LinkedBinaryTree::expandExternal(const Position &p) {
        Node *v = p.v;
        v->left=new Node;
        v->left->par=v;
        v->left->ele=++n;
        v->right=new Node;
        v->right->par=v;
        v->right->ele=++n;
    }
    
    LinkedBinaryTree::PositionList LinkedBinaryTree::positions(int trv) const {
        PositionList pl;
        if (trv==1)
            preorder(_root,pl);
        else if (trv==2)
            inorder(_root,pl);
        else postorder(_root,pl);
        return PositionList(pl);
    }
    
    void LinkedBinaryTree::preorder(Node *v, PositionList &pl) const {
        pl.push_back(Position(v));
        if (v->left!=NULL)
            preorder(v->left,pl);
        if (v->right!=NULL)
            preorder(v->right,pl);
    }
    
    void LinkedBinaryTree::postorder(Node *v, PositionList &pl) const {
        if (v->left!=NULL)
            preorder(v->left,pl);
        if (v->right!=NULL)
            preorder(v->right,pl);
        pl.push_back(Position(v));
    }
    
    void LinkedBinaryTree::inorder(Node *v, PositionList &pl) const {
        if (v->left!=NULL)
            preorder(v->left,pl);
        pl.push_back(Position(v));
        if (v->right!=NULL)
            preorder(v->right,pl);
    }
    
    
    1. linked_binary_tree_main.cc
    #include <iostream>
    #include "linked_binary_tree.h"
    using namespace std;
    
    int main() {
    
        LinkedBinaryTree lbt;
        lbt.addRoot();
        cout << "post addRoot()" << endl;
        LinkedBinaryTree::Position pr = LinkedBinaryTree::Position(lbt.root()); // --> STATEMENT 1
        cout << "post lbt.root()" << endl;
        //LinkedBinaryTree::Position pr = lbt.root();  // --> STATEMENT 2
        lbt.expandExternal(pr); 
        cout << "LinkedBinaryTree.size() :- " << lbt.size() << endl;
    
        // 1-preorder 2-inorder 3-postorder
        auto iter=lbt.positions(3);
        auto cbeg=iter.cbegin();
        auto cend=iter.cend();
    
        for (; cbeg!=cend; cbeg++) {
            cout << cbeg->operator*() << " ";
        }
        cout << endl;
    
        return 0;
    
    }
    
    
    1. 执行linked_binary_tree_main的结果
    post addRoot()
    LinkedBinaryTree::root() --> STATEMENT 3
    Position constr --> STATEMENT 4
    post lbt.root()
    LinkedBinaryTree.size() :- 3
    Position constr
    Position constr
    Position constr
    2 3 1 
    
    

    笔记:

    1. 声明 1

      LinkedBinaryTree::Position pr = LinkedBinaryTree::Position(lbt.root()); // --> 声明 1

      一个。 lbt.root() 实际上返回了 LinkedBinaryTree::Position 实例。
      湾。没有接受 Position 实例的 LinkedBinaryTree::Position 构造函数。相反,它具有以下内容:

      位置(节点 *_v=NULL):v(_v) { cout << "位置常数" << endl;}

      它需要一个指向 Node 参数的指针。然而 STATEMENT 1 显示调用了 LinkedBinaryTree::Position(Node *v) 构造函数。
      C。如果您注释掉 STATEMENT 1 并使用 STATEMENT 2,那当然也可以。

      那么为什么声明 1 有效呢?

      欣赏任何见解。
      谢谢。

【问题讨论】:

  • 这会有点长-- 老实说,如果您唯一关心的是调用哪个构造函数,您可能已经删除了大量的代码。这些类的内部是否正在构建二叉树并不重要——这些都是可以消除的噪音。
  • @PaulMcKenzie 对此感到抱歉。考虑一下也可以,因为有时会要求所有代码,以便审阅者可以自己测试。那么有什么见解吗?
  • 在不相关的注释上:using namespace std; is a bad habit 在正常情况下。在头文件中这样做应该被认为是完全错误的。
  • @yapkm01 -- LinkedBinaryTree::Position pr = LinkedBinaryTree::Position(lbt.root()); 您没有测试所有可能的构造函数,例如 Position 的复制构造函数。此外,Position root() const; -- root 成员函数返回实例的副本,而不是实际实例。
  • 您接受的答案正是我在您没有跟踪的内容中给您的提示——复制构造函数。

标签: c++ binary-tree c++20


【解决方案1】:

您看到的构造函数不是您认为的构造函数。

STATEMENT 1 中的构造函数是(编译器生成的)复制构造函数。

打印输出Position constr 的构造函数发生在LinkedBinaryTree::root 函数中:

return Position(_root);

一旦我created a more minimal example(以及一些额外的输出),这更容易看到。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 2014-04-22
    • 1970-01-01
    • 2013-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多