-2

This will be a bit lengthy but anyhow i tried my best to simplify it using code.
I am building a binary tree but noticed something peculiar.

  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. Results executing 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 

Note:

  1. Statement 1

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

a. The lbt.root() actually returned LinkedBinaryTree::Position instance.
b. There is no LinkedBinaryTree::Position constructor which takes in a Position instance. Instead it has the following:

Position(Node *_v=NULL): v(_v) { cout << "Position constr" << endl;}

which is it takes a pointer to a Node argument. Yet STATEMENT 1 works showing that LinkedBinaryTree::Position(Node *v) constructor is called.
c. If you comment out STATEMENT 1 and use STATEMENT 2 that of course would work as well.

So why does STATEMENT 1 works?

Appreciate any insight.
Thanks.

yapkm01
  • 3,590
  • 7
  • 37
  • 62
  • *This will be a bit lengthy* -- In all honesty, you could have removed vast chunks of that code if your only concern is which constructor gets called. It doesn't matter if the internals of those classes are building a binary tree -- that's all noise that could have been eliminated. – PaulMcKenzie Sep 12 '22 at 04:17
  • @PaulMcKenzie Sorry for that. Thought might as well put all in since at times there's been request for all the codes so that reviewer can test it out themselves. So any insight? – yapkm01 Sep 12 '22 at 04:19
  • On an unrelated note: [`using namespace std;` is a bad habit](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) in normal cases. Doing it in a header file should be considered plain wrong. – Some programmer dude Sep 12 '22 at 04:27
  • @yapkm01 -- `LinkedBinaryTree::Position pr = LinkedBinaryTree::Position(lbt.root());` You are not testing all the possible constructors, such as the copy constructor for `Position`. Also, `Position root() const;` -- the `root` member function returns a copy of the instance, not the actual instance. – PaulMcKenzie Sep 12 '22 at 04:29
  • @PaulMcKenzie Look at the results - STATEMENT 4. That is the output from the LinkedBinaryTree::Position(Node *v). So this constructor was executed from STATEMENT 1. – yapkm01 Sep 12 '22 at 04:35
  • You asked about statement 1, and why does it "work" (whatever "work" means). And to that, why not run your code in a debugger to see the chain of events that causes statement 1 to "work"? – PaulMcKenzie Sep 12 '22 at 04:36
  • @PaulMcKenzie What i am trying to say is simply this. STATEMENT 1 LinkedBinaryTree::Position pr = LinkedBinaryTree::Position(lbt.root()); when invoked called the LinkedBinaryTree::Position(Node *v). STATEMENT 4 which is the output of LinkedBinaryTree::Position(Node *v) constructor proves it. Issue is the argument between them is different. – yapkm01 Sep 12 '22 at 04:38
  • 2
    The answer you accepted is exactly the hint I gave you in what you were not tracking -- the copy constructor. – PaulMcKenzie Sep 12 '22 at 04:49

1 Answers1

1

The constructor you're seeing is not the one you think it is.

The constructor in STATEMENT 1 is the (compiler-generated) copy-constructor.

The constructor printing the output Position constr happens in the LinkedBinaryTree::root function:

return Position(_root);

This was much easier to see once I created a more minimal example (together with some extra output).

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621