473,563 Members | 2,747 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Member struct declared in base, defined in derived class

I'm messing around with using mixin-layers (look for papers by Yannis
Smaragdakis and Don Batory) to define data structures. One issue is
that nodes tend to have pointers to other nodes - the pointers have to
point to the full node type, and have to be referenced before that
full node type is known.

One solution is to use the 'fixpoint construction' to get an apparent
circular dependency...

class c_Final : public c_Layer2< c_Layer1 <c_Final {};

I'm always a bit nervous about this, though, so I was wondering about
alternatives. It seemed to me that all I really need to do is to
declare the final node type in a base class, but define it in a
derived class.

So, I tried the following experiment...

class c_Base
{
public:
struct c_Full_Node;

struct c_Node
{
c_Full_Node *m_Parent;
};
};

class c_Derived1 : public c_Base
{
public:
struct c_Base::c_Full_ Node : public c_Base::c_Node
{
int m_Data;
};

typedef c_Base::c_Full_ Node c_Full_Node;
};

//class c_Derived2 : public c_Base
//{
// public:
// struct c_Base::c_Full_ Node : public c_Base::c_Node
// {
// char m_Data;
// };
//
// typedef c_Base::c_Full_ Node c_Full_Node;
//};

//////////

int main(int argc, char* argv[])
{
c_Derived1::c_F ull_Node l_Node1;

l_Node1.m_Paren t = 0;
l_Node1.m_Data = 0;

//c_Derived2::c_F ull_Node l_Node2;

//l_Node2.m_Paren t = 0;
//l_Node2.m_Data = 0;

return EXIT_SUCCESS;
}

The commented out code does not compile, for fairly obvious reasons -
it tries to create a second definition of c_Base::c_Full_ Node.

This seems like a perfect solution to the problem to me, since it
doesn't give the appearance of peering into the future. I haven't
wrapped it up in templates to do real mixin layer stuff yet, but I
can't see any *additional* reasons why that shouldn't work.

What can I say. I've learned to think twice before saying "that would
never work" with C++, or I would never have even tried this
experiment.

That said, all I have proved is that it seems to work with Microsoft
Visual C++ 2003. This doesn't mean that it *should* work, according to
the standard.

So - can anyone tell me whether this is standard-compliant, portable
code? I haven't got a clue myself.

Apr 3 '07 #1
2 2294

Applying this with mixin layer templates turned out to be a little
fiddly, because the base for the mixin layers cannot be templated. I
have built a working example, though.

It does require more code to do the composition than using the
fixpoint thing, since it needs the initial struct to be defined before
the composition, and then needs 'capping off' at the end with another
non-template struct.

Also, it looks like there's no real point to this when the base class
for the composition isn't templated. In the following example,
c_Base::c_Full_ Node could have been defined outside of c_List, and it
is probably less confusing to do so.

I have achieved my goal, in that I can build data structures using
mixin layers but without using the fixpoint construct anyway, and I'm
kicking myself for not realising it's this simple.

The question remains, though - does the C++ standard require that it
is legal to have a struct/class that is declared in a base class, but
defined in its derived class?

The full example follows...
namespace mixins
{
// Required base class for starting the mixin
// composition - defines the empty base for the
// node structure that other mixin layers refine.
template<class B struct c_List_Base : public B
{
typedef typename B::c_Full_Node c_Full_Node;

struct c_Node { };
};

template<class B struct c_List_Fwd : public B
{
typedef typename B::c_Full_Node c_Full_Node;

struct c_Node : public B::c_Node
{
c_Full_Node *m_Next;
};
};

template<class B struct c_List_Bwd : public B
{
typedef typename B::c_Full_Node c_Full_Node;

struct c_Node : public B::c_Node
{
c_Full_Node *m_Prev;
};
};

template<class B, class T struct c_List_Data : public B
{
public:
typedef typename B::c_Full_Node c_Full_Node;

struct c_Node : public B::c_Node
{
T m_Data;
};
};
};

//////////
// Composition needs more code using this technique, though the
// principle is simple enough.

struct c_Base
{
// We need a new initial mixin layer for each composition,
// since we need a new c_Full_Node type declaration for
// composition or else the definitions would conflict.
struct c_Full_Node;

// May as well define the empty base for the node here as well
struct c_Node {};
};

// Step by step composition
struct c_List_000 : public mixins::c_List_ Base< c_Base {};
struct c_List_001 : public mixins::c_List_ Fwd < c_List_000 {};
struct c_List_002 : public mixins::c_List_ Bwd < c_List_001 {};
struct c_List_003 : public mixins::c_List_ Data< c_List_002, int {};

// Cap off the composition

struct c_List : public c_List_003
{
struct c_Base::c_Full_ Node : public c_List_003::c_N ode {};
typedef c_Base::c_Full_ Node c_Node;
};

//////////

int main(int argc, char* argv[])
{
c_List::c_Full_ Node l_Node1;

l_Node1.m_Next = 0;
l_Node1.m_Prev = 0;
l_Node1.m_Data = 0;

return EXIT_SUCCESS;
}

Apr 3 '07 #2

The whole of this thread so far turns out to be pointless. What I
should be doing is...

struct c_Node;
struct c_List : public c_Mixin2< c_Mixin1< c_Node* {};
struct c_Node : public c_List::c_Node {};

That is, the mixin layers simply accept a node identifier type as one
of the arguments at the start. This can be a pointer to a struct that
hasn't been defined yet (as above) or it could be an integer
identifier or whatever.

If the node identifier is a pointer, simply forward-reference the
pointed-to type.

This creates a problem with any algorithms that are defined by the
mixin-layers to work on the data structure, since they cannot assume
that node IDs are pointers. This can be resolved by using policies
passed to the appropriate mixin layers as arguments. Policy members
might be simple inlines to access fields using "->", or they might be
more complex functions to look nodes up in a separate container or
file.

Interesting, how policies and mix-in layers can complement each other.
Though since they're basically the template versions of existing OOP
techniques, it's no big surprise.

Apr 3 '07 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
1981
by: Luca | last post by:
Hi, I have a quite complex question to ask you: I have defined a base class where I would like to have a map holding pointers to member functions defined in derived classes. To be more precise I would like my base class to have the following member: map<string, pointer_to_member_function> myClassMap;
3
2250
by: Doug Eleveld | last post by:
Hi Everyone, I have been playing aroung with 'object-oriented' C for a while now and I have come up with an interesting way to simulate C++ inheritance and non-member functions in C in a 100% typesafe way. The object derivation is a bit cloudy, but the code is fairly repetitive and doesn't seem to be terribly error prone. Maybe some...
2
7842
by: Mark Sisson | last post by:
Hi all. SITUATION ================ 1. I have a base class with a member variable that's an object 2. I have several classes that inherit from the base class. 3. There are several methods in the base class that modify the member variable 4. I would like to have the inherited classes override the member variable with a new var that's a...
6
4397
by: Bill Rubin | last post by:
The following code snippet shows that VC++ 7.1 correctly compiles a static member function invocation from an Unrelated class, since this static member function is public. I expected to compile the same invocation from a DistantlyRelated class. What actually happened was that the compiler produced: error C2247: 'A::function' not accessible...
9
1644
by: Mirko Puhic | last post by:
Is there a way to properly do this? struct Derived; struct Base{ Derived der; };
7
3791
by: WaterWalk | last post by:
Hello. I thought I understood member function pointers, but in fact I don't. Consider the following example: class Base { public: virtual ~Base() {} }; class Derived : public Base {
15
3065
by: =?Utf-8?B?R2Vvcmdl?= | last post by:
Hello everyone, I met with a strange issue that derived class function can not access base class's protected member. Do you know why? Here is the error message and code. error C2248: 'base::~base' : cannot access protected member declared in
2
1778
by: Peng Yu | last post by:
Hi, In the following code, the 'copy' member function works. But the '=' operator does not work. Can somebody let me know why a member function is different from an operator. Thanks, Peng #include <iostream>
10
4057
by: blangela | last post by:
If I pass a base class object by reference (likely does not make a difference here that it is passed by reference) as a parameter to a derived class member function, the member function is not allowed to access the protected data members of the base object. This surprises me. Can someone explain why this is? I suspect there is a good...
0
7664
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7583
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
1
7638
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
6250
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
0
5213
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3642
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
3626
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
1198
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
923
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.