specifying ptr to instance of >=2 classes

S

Suzanne Vogel

** Is there a way (C++ syntax) to specify that a pointer should refer to
an object that derives from *two* specific classes?

eg, Suppose I have two classes, 'A' and 'B', and I want to specify that
pointer 'p' refers to an object derived from both. I *don't* want to
invent some class 'Bar' that derives from 'A' and 'B', and specify that
pointer 'p' should derive from that class 'Bar'.

class A
{ ...
}

class B
{ ...
}

class Example
{
public:
A* p; // but I also want p to refer to an object derived from B
}

class Foo : public A, public B
{ ...
}

void main(int argc, char** argv)
{
Example ex;
ex.p = new Foo(); // set Example::p to an object derived from A and B
}

Thanks,
Suzanne
 
J

Jonathan Mcdougall

** Is there a way (C++ syntax) to specify that a pointer should refer to
an object that derives from *two* specific classes?

eg, Suppose I have two classes, 'A' and 'B', and I want to specify that
pointer 'p' refers to an object derived from both. I *don't* want to
invent some class 'Bar' that derives from 'A' and 'B', and specify that
pointer 'p' should derive from that class 'Bar'.


Not easily. Note that Modern C++ Design by Andrei Alexandrescu would
be a good idea to buy. Good luck!


// your two base classes
class A
{};

class B
{};

// a good class
class C : public A, public B
{
};

// a bad class
class D
{};


// test whether T converts to U,
// that is, if T is derived from U
// taken from Modern C++ Design
//
template <class T, class U>
class Conversion
{
typedef char Small;
class Big {char dummy[2];};

static Small Test(U);
static Big Test(...);
static T MakeT();

public:
enum { exists = sizeof(Test(MakeT())) == sizeof(Small) };
};

// catches T == T
//
template <class T>
class Conversion<T, T>
{
public:
enum { exists = false };
};

// issues 'customizable' error
// this one is used for 'false' and has a default ctor
// adapted from MC++D
//
template <bool>
class Check
{
public:
Check() {}
};

// this one is used for 'true' and has a catch-all ctor
//
template <>
class Check<true>
{
public:
Check(...) {}
};


// your pointer class
// Base1 and Base2 are the two required base classes
// T is the pointer type
//
template <class Base1, class Base2, class T>
class MyPointer
{
T* t_;

class ERROR_must_inherit {};
public:
MyPointer(T *t)
{
// must name all the objects since the two statements will be taken
// as function declarations
ERROR_must_inherit the_error;

Check<Conversion<const T, const Base1>::exists > dummy1(the_error);
Check<Conversion<const T, const Base2>::exists > dummy2(the_error);
}
};


int main()
{
MyPointer<A, B, D> p(new D);
MyPointer<A, B, C> p(new C);
}


The first statement will give something like (well.. on Comeau)

line 77: error: no instance of constructor
"Check<<unnamed>>::Check [with <unnamed>=false]" matches the
argument list

The argument types that you used are:
(MyPointer<A, B, D>::ERROR_must_inherit)
Check<Conversion<const T, const Base1>::exists > dummy1(the_error);
^
detected during instantiation of
"MyPointer<Base1, Base2, T>::MyPointer(T *)
[with Base1=A, Base2=B, T=D]" at line 86

line 78: error: no instance of constructor
"Check<<unnamed>>::Check [with <unnamed>=false]" matches the
argument list

The argument types that you used are:
(MyPointer<A, B, D>::ERROR_must_inherit)
Check<Conversion<const T, const Base2>::exists > dummy2(the_error);
^
detected during instantiation of
"MyPointer<Base1, Base2, T>::MyPointer(T *)
[with Base1=A, Base2=B, T=D]" at line 86


Maybe someone has a better solution, or you could adapt this one to
your needs.


Jonathan
 
J

Jeff F

Suzanne,

Suzanne Vogel said:
** Is there a way (C++ syntax) to specify that a pointer should refer to
an object that derives from *two* specific classes?

eg, Suppose I have two classes, 'A' and 'B', and I want to specify that
pointer 'p' refers to an object derived from both. I *don't* want to
invent some class 'Bar' that derives from 'A' and 'B', and specify that
pointer 'p' should derive from that class 'Bar'.

Your instincts are correct.
class A
{ ...
}

class B
{ ...
}

class Example
{
public:
A* p; // but I also want p to refer to an object derived from B
}

class Foo : public A, public B
{ ...
}

This class heirarchy is inverted. What you would like is for A and B to
inherit from an abstract base class, which has the interface that you would
like to access polymorphically.

class Base
{
public:
Base(){}
virtual ~Base(){}

virtual void SomeFnc()const=0;
};

class A : public Base
{
public:
A():Base(){}

virtual ~A(){}

virtual void SomeFnc()const{ ... }
};


class B : public Base
{
public:
B():Base(){}

virtual ~B(){}

virtual void SomeFnc()const{ ... }
};

class Example
{
Base* mBasePtr; // avoid public members
public:
Example():mBasePtr(NULL){} // always initialize members

~Example(){ delete mBasePtr; } // avoid memory leaks

void NewA(){ delete mBasePtr; mBasePtr = new A(); }
void NewB(){ delete mBasePtr; mBasePtr = new B(); }

void DoSomeFnc(){ if( mBasePtr ) mBasePtr->SomeFnc(); }
};
void main(int argc, char** argv)
{
Example ex;
ex.p = new Foo(); // set Example::p to an object derived from A and B

Example ex;

ex.DoSomeFnc(); // safely does nothing

ex.NewA(); // new's an A

ex.DoSomeFnc(); // calls A::SomeFnc

ex.NewB(); // new's a B

ex.DoSomeFnc(); // calls B::SomeFnc

I would suggest reading Bruce Eckel's "Thinking in C++" and Stroustrup's
"The C++ Programming Language" to get a better understanding of C++'s
facilities and how to use them effectively.
 
T

tom_usenet

** Is there a way (C++ syntax) to specify that a pointer should refer to
an object that derives from *two* specific classes?

Two dynamic casts? Are you talking about the static type of the
pointer, or the dynamic type of the object pointed to?
eg, Suppose I have two classes, 'A' and 'B', and I want to specify that
pointer 'p' refers to an object derived from both. I *don't* want to
invent some class 'Bar' that derives from 'A' and 'B', and specify that
pointer 'p' should derive from that class 'Bar'.

class A
{ ...
}

class B
{ ...
}

class Example
{
public:
A* p; // but I also want p to refer to an object derived from B

Make that private, and add:

template <class T>
void setP(T* t)
{
B* bcheck = t; //error if not derived from b
p = t; //error if not derived from a
}
}

class Foo : public A, public B
{ ...
}

void main(int argc, char** argv)
{
Example ex;
ex.p = new Foo(); // set Example::p to an object derived from A and B

ex.setP(new Foo());
}

Not sure why you would want this though, and not sure if you want a
runtime check. For a runtime check:

void setP(A* ap)
{
dynamic_cast<B&>(*ap); //throws if not derived from B&
p = ap;
}

Tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,143
Messages
2,570,822
Members
47,368
Latest member
michaelsmithh

Latest Threads

Top