Home > front end >  C : Why Position constructor are called when the argument type does not match?
C : Why Position constructor are called when the argument type does not match?

Time:09-12

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.

CodePudding user response:

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

  • Related