[comp.lang.c++] Virtual Base Class problem using C++/NIH - any pointers ?

mcardle@prl.philips.nl (Owen McArdle) (03/08/91)

[Apologies for those of you who are reading this twice, I've broadened
the distbn. to world, hoping for some more reaction]

Ok folks,

 I've been banging my head against this one for too long now,
and getting nowhere. I figure at this stage that either I'm 
missing some really obvious coding error, or I really have a 
problem with C++/NIH. To draw on your collective wisdom would 
seem the best way forward, so here goes.

 First the base: 
NIH 3.0
HP/Apollo DN[34]000, running sr10.2/10.3
CC = Domain/C++ V2.1.0;CC (C++), revision 1.0, 11/05/90
cc = Domain/C Version 6.8

 Now the problem:
 I was trying to make use of Multiple Inheritance, and found myself
with the need to make use of a few virtual base classes "in series",
Eg:
 A -deriv-> B -v_deriv-> C -v_deriv-> D

 ignoring all other derived classes. Creating an instance of D
is OK, but certain actions using it are not. I include a stripped 
version of the C++ code below: 

/////////////////////////////////////////////////////////////////////
#include "Object.h"
#include "String.h"
#include "Set.h"
#include "nihclconfig.h"

#ifndef MI
#define MI
#endif

class Node : public String
{	DECLARE_MEMBERS(Node);
	int		soon, late;
protected:
	virtual void storer(OIOofd&) const {}
	virtual void storer(OIOout&) const {}
public:
	Node();
	Node(const String&, int ni, int no);
	virtual void	printOn(ostream& strm =cout) const;
};

#define	THIS		Node
#define	BASE		String
#define BASE_CLASSES	BASE::desc()
#define MEMBER_CLASSES
#define VIRTUAL_BASE_CLASSES

DEFINE_CLASS(Node, 0, "Node.cxx", NULL, NULL);

Node::Node()
{	late = soon = -2;
	cerr << "In Node::Node()\n";
}

Node::Node(const String& name, int ni, int no)
: String(name)
{	late = ni;
	soon = no;
	cerr << "In Node::Node(s,i,o)\n";
}

void 
Node::printOn(ostream& strm) const
{	strm << " Node \nSoon =\t" << soon << "\tLate =\t" << late << endl;
}

Node::Node(OIOifd& fd) : Object(fd), String(fd) {}
Node::Node(OIOin& strm) : Object(strm), String(strm) {}
/////////////////////////////////////////////////////////////////////

class PrimNode : public VIRTUAL Node
{	DECLARE_MEMBERS(PrimNode);
protected:
	virtual void storer(OIOofd&) const {}
	virtual void storer(OIOout&) const {}
public:
	PrimNode();
	PrimNode(const String& name, int ni = 2, int no = 1);
	virtual void		printOn(ostream& strm =cout) const;
};

#undef THIS
#define	THIS		PrimNode
#undef BASE
#define	BASE		Node
#undef BASE_CLASSES
#define BASE_CLASSES	BASE::desc()
#undef MEMBER_CLASSES
#define MEMBER_CLASSES
#undef VIRTUAL_BASE_CLASSES
#define VIRTUAL_BASE_CLASSES	BASE::desc()

DEFINE_CLASS(PrimNode, 1, "PrimNode.cxx", NULL, NULL); 

PrimNode::PrimNode()
{	cerr << "In PrimNode::PrimNode()\n" << endl;
}

PrimNode::PrimNode(const String& name, int ni, int no)
: Node(name,ni,no)
{	cerr << "In PrimNode::PrimNode(s,i,o)\n";
}

void PrimNode::printOn(ostream& strm) const
{	strm << " Prim ";
	Node::printOn(strm);
}

PrimNode::PrimNode(OIOifd& fd) : Object(fd), Node(fd) {}
PrimNode::PrimNode(OIOin& strm) : Object(strm), Node(strm) {}
/////////////////////////////////////////////////////////////////////

class AssignNode : public VIRTUAL PrimNode
{                                       
	DECLARE_MEMBERS(AssignNode);
protected:
	virtual void storer(OIOofd&) const {}
	virtual void storer(OIOout&) const {}
public:
        AssignNode(const String& name, int ni = 1, int no = 1);
	virtual void		printOn(ostream& strm =cout) const;
};

#undef THIS
#define	THIS		AssignNode
#undef BASE
#define	BASE		PrimNode
#undef BASE_CLASSES
#define BASE_CLASSES	BASE::desc()
#undef MEMBER_CLASSES
#define MEMBER_CLASSES
#undef VIRTUAL_BASE_CLASSES
#define VIRTUAL_BASE_CLASSES	BASE::desc()

DEFINE_CLASS(AssignNode, 0, "AssignNode.cxx", NULL, NULL); 

AssignNode::AssignNode(const String& name, int ni, int no)
: Node(name,ni,no), PrimNode(name,ni,no)
{	cerr << "In AssignNode::AssignNode(s,i,o)\n";
}

void AssignNode::printOn(ostream& strm) const
{	strm << " Assign ";
	Node::printOn(strm);
}

AssignNode::AssignNode(OIOifd& fd) : Object(fd), Node(fd), PrimNode(fd) {}
AssignNode::AssignNode(OIOin& strm) : Object(strm), Node(strm),PrimNode(strm) {}

/////////////////////////////////////////////////////////////////////


main()
{
	Set	nTable;

	AssignNode *an = new AssignNode("ASGN");

	cout << "Hash result: " << an->hash() << endl;
	cout << "Hash result: " << String::castdown((Object*)an)->hash() << endl;

	nTable.add(*an);

	cout << nTable;
}

/////////////////////////////////////////////////////////////////////

running this program gets me:

In Node::Node(s,i,o)
In PrimNode::PrimNode(s,i,o)
In AssignNode::AssignNode(s,i,o)
Hash result: 1095976778
Hash result: 1095976778
Memory fault

 with traceback:

#> tb
Process        26728 (parent 26375, group 26728)
Time           91/03/06.11:34(NED)
Program        /local_user/mcardle/src/cxx/test/EXPM2
Status         00040004: reference to illegal address (OS/MST manager)
In routine     "String::hash" line 544
Called from    "Set::findIndexOf" line 103
Called from    "Set::add" line 137
Called from    "main" line 142
Called from    "unix_$main" line 114
Called from    "_start" line 132
Called from    "PM_$CALL" line 176
Called from    "pgm_$load_run" line 903
Called from    "pgm_$invoke_uid_pn" line 1124

/////////////////////////////////////////////////////////////////////

 Stepping into the routine Set::add, up to String::hash, I can see that
the values of the String variables (len, p) are completely wrong. Why I 
haven't worked out yet. Any ideas ? Does it seem to work for you ?
I have tried a similar structure using just C++ constructs, and it works
OK, but like I say I may just be blindly missing something here. 

All suggestions gratefully accepted,
Replies by e-mail please, should something of general interest result I'll
post again.
Is mise le meas



Owen P.McArdle		|| e-mail : mcardle@prl.philips.nl
Philips Research Labs.	|| 'phone : +31-40-742824
Eindhoven 		|| quote  : "Oh no, not again"
The Netherlands		|| vice	  : GS450L