I am trying to call virtual method at the constructer of parent class and I want to that of child methods. Let me explain:
I need to read words from line by line from a text file and insert them a search tree one by one. I have tree child classes: DictionaryBST
,DictionaryAVLTree
,Dictionary23Tree
. I implemented their own insert methods.
Here the header code of my parent class which is DictionarySearchTree:
class DictionarySearchTree {
public:
DictionarySearchTree();
DictionarySearchTree(string dictionaryFile);
virtual ~DictionarySearchTree();
virtual void insert(string word);
virtual void search(string word, int& numComparisons, bool& found) const;
virtual void search(string queryFile, string outputFile) const;
virtual void inorderTraversal();
protected:
TreeNode* root;
int size;
void searchNode(TreeNode* node, string word, int& numComparisons, bool& found) const;
void virtual insertNode(TreeNode*& node, string word);
void postTraversalDeletation(TreeNode*& node);
void inorder(TreeNode* node);
void getHeight(TreeNode* node, int& height);
};
Here is the constructer:
DictionarySearchTree::DictionarySearchTree(string dictionaryFile) {
root = NULL;
size = 0;
istringstream stream;
ifstream infile;
string line;
infile.open(dictionaryFile);
while (getline(infile, line)) {
insert(line); // This methods should call child's ones.
}
infile.close();
}
My main method:
int main() {
DictionarySearchTree* tree = new DictionaryBST("./dictionary.txt");
DictionarySearchTree* avlTree = new DictionaryAVLTree("./dictionary.txt");
DictionarySearchTree* twoThreeTree = new Dictionary23Tree("./dictonary.txt");
}
I don't want to write constructer methods to each one, as well. Can some help me?
Don't call virtual
functions in a constructor or destructor. The reason for this is that during the constructor of DictionarySearchTree
, the runtime type of the current object this
is always DictionarySearchTree
and never any more derived type. This means that virtual
function calls made during the constructor will always be bound to those defined or inherited by DictionarySearchTree
, and nothing more. There are good reasons for this and they're discussed further in this Q/A
The best thing in your case would be to populate the dataset after constructing the most-derived object. For example, you could add a void populate(string dictionaryFile)
member function to DictionarySearchTree
that calls all the virtual
member functions you want. Then, importantly, call this populate()
function after you have constructed the most derived object, as a separate step.
int main() {
std::unique_ptr<DictionarySearchTree> tree = std::make_unique<DictionaryBST>();
std::unique_ptr<DictionarySearchTree> avlTree = std::make_unique<DictionaryAVLTree>();
std::unique_ptr<DictionarySearchTree> twoThreeTree = std::make_unique<Dictionary23Tree>();
tree.populate("./dictionary.txt");
avlTree.populate("./dictionary.txt");
twoThreeTree.populate("./dictionary.txt");
}
Note that smart pointers such as std::unique_ptr
should be prefered over raw owning pointers for dynamic memory management.
The ISO C++ FAQ on Strange Inheritance also discusses this issue and suggests two-phase initialization as I've shown here as a work-around.