Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

C++: Why Position constructor are called when the argument type does not match?

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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.

>Solution :

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).

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading