Topic: Passing a class name as parameter


Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Fri, 18 Sep 92 14:25:34 GMT
Raw View
In article <1992Sep18.060641.29183@jyu.fi> sakkinen@jyu.fi (Markku Sakkinen)
writes:
> In article <1992Sep17.141244.29693@osf.org> laribi@vadier.gr.osf.org (Laribi
Youcef) writes:
> >I want to pass a class name as an argument to a function which creates
> >an object
> >from that class, since i don't want to write the same function for each
class.
> >Is this can be achieved in C++? If yes, how ? thanks to respond.
>
> No way.
> You rather need a language in which classes are themselves fully-fledged
> objects, e.g. Smalltalk or CLOS.
>

Try template, it's the only way in C++.

David Shang




Author: shang@corp.mot.com (David (Lujun) Shang)
Date: Fri, 18 Sep 92 14:42:51 GMT
Raw View
In article <1992Sep17.141244.29693@osf.org>:
> I want to pass a class name as an argument to a function which creates
> an object from that class, since i don't want to write the same function
> for each class. Is this can be achieved in C++? If yes, how ? thanks to
> respond.
>

You can try templates, it may help you a little. The limit is that you
must use a uniform input format for each class that uses the template.

A way to work arround is to create the object when call the template
function:

   template <class T> HANDLE<T> create ( T *);

   HANDLE<T1> h1 = create ( new T1(p1,p2,...) );
   HANDLE<T2> h2 = create ( new T2(p) );
   ...

David Shang




Author: jbuck@forney.berkeley.edu (Joe Buck)
Date: 18 Sep 92 20:59:42 GMT
Raw View
In article <1992Sep17.141244.29693@osf.org> laribi@vadier.gr.osf.org
(Laribi Youcef) writes:
>>I want to pass a class name as an argument to a function which creates
>>an object from that class, since i don't want to write the same function
>>for each class.  Is this can be achieved in C++? If yes, how ? thanks to
>>respond.

In article <1992Sep18.060641.29183@jyu.fi> sakkinen@jyu.fi (Markku
Sakkinen) writes:
>No way.
>You rather need a language in which classes are themselves fully-fledged
>objects, e.g. Smalltalk or CLOS.

Way!  (Apologies to those who are tired of "Wayne's World").  See my
paper in the most recent "C++ at Work" conference proceedings on the
Ptolemy system, which solves this problem among others.

If you can live with the restriction that all objects that can be
dynamically created in this manner (by passing a string that gives their
class name), it can be done, as follows:

First, each such class should implement a clone() method, which might be

Block* MyClass::clone() const { return new MyClass;}

or possibly

Block* MyClass::clone() const { return new MyClass(*this);}

where Block is the name of the baseclass.  In the baseclass we have

class Block {
public:
 virtual Block* clone() const = 0;
 ...
};

Thanks to the recent reform adopted by the ANSI C++ committee, you can
have it return MyClass* instead of Block*, which lets you get rid of a lot
of downcasting.

Second, create one global (actually, file-static) instance of each class.
This prototype instance will serve, in effect, as the metaclass object.

Third, create a class to manage a data structure, called, say, KnownBlock.
All its methods will be static, except for the constructor, and the
constructor is used only for its side effect.  The side effect is to
insert a prototype instance into the known list (which may be a hash
table, b-tree, or whatever -- it associates class names with prototype
instances).  So to get class SuperBlock added to the list, I add the
following to the file that implements SuperBlock the following:

static SuperBlock proto;

static KnownBlock entry(proto, "SuperBlock");

The effect of this is that the known list of blocks is created before
main() is started.  Now, to clone an arbitrary block, I provide the
static methods

const Block* KnownBlock::find(const char* name);

This returns a pointer to the prototype with class name "name", if it
exists.  Then we can implement the static method

Block* KnownBlock::clone(const char* name) {
 const Block* proto = find(name);
 return proto ? proto->clone() : 0;
}

Now we can extend the system by incremental linking.  The incremental
linking module links in a new object file into the current executable and
calls any constructors for global objects -- we have this procedure
working under both g++ and cfront for a number of platforms, both BSD-ish
and SysV-ish.  A typical object file will include the methods and
prototype instance for a new derived class of Block.  The result is that
new types of Blocks can be added to the system dynamically, and
KnownBlock::clone will then be able to create instances of them.

This is used in a block-oriented simulation and software prototyping
system.  The user clicks on an icon representing a functional block, and
an instance of that block is created.  If the class name in question is
not present in the executable, it is dynamically loaded.

(I am simplifying considerably to explain the concept).

I said earlier that the prototype object serves as a sort of metaclass;
that is, inquiries on the properties of a particular functional block
can be handled by calling virtual functions on the object returned by
the KnownBlock::find method.

--
Joe Buck jbuck@ohm.berkeley.edu




Author: jbuck@forney.berkeley.edu (Joe Buck)
Date: 18 Sep 92 22:33:55 GMT
Raw View
Following up my own article:

In article <19dfvuINN4mv@agate.berkeley.edu> jbuck@forney.berkeley.edu (Joe Buck) writes:
...
>If you can live with the restriction that all objects that can be
>dynamically created in this manner (by passing a string that gives their
>class name), it can be done, as follows:

That should read

>class name) have a common base class, it can be done, as follows:

--
Joe Buck jbuck@ohm.berkeley.edu




Author: sdm@cs.brown.edu (Scott Meyers)
Date: Sat, 19 Sep 1992 01:51:06 GMT
Raw View
In article <19dfvuINN4mv@agate.berkeley.edu> jbuck@forney.berkeley.edu (Joe Buck) writes:
| In article <1992Sep17.141244.29693@osf.org> laribi@vadier.gr.osf.org
| (Laribi Youcef) writes:
| >>I want to pass a class name as an argument to a function which creates
| >>an object from that class, since i don't want to write the same function
| >>for each class.  Is this can be achieved in C++? If yes, how ? thanks to
| >>respond.
|
| If you can live with the restriction that all objects that can be
| dynamically created in this manner (by passing a string that gives their
| class name) [inherit from a common base class -- sdm], it can be done, as
| follows:
|
| First, each such class should implement a clone() method...

...

| Second, create one global (actually, file-static) instance of each class.
| This prototype instance will serve, in effect, as the metaclass object.
|
| Third, create a class to manage a data structure, called, say, KnownBlock.
| All its methods will be static, except for the constructor, and the
| constructor is used only for its side effect.  The side effect is to
| insert a prototype instance into the known list (which may be a hash
| table, b-tree, or whatever -- it associates class names with prototype
| instances).  So to get class SuperBlock added to the list, I add the
| following to the file that implements SuperBlock the following:
|
| static SuperBlock proto;
|
| static KnownBlock entry(proto, "SuperBlock");
|
| The effect of this is that the known list of blocks is created before
| main() is started.

I'm not convinced.  This sounds a lot like it's an instance of what I call
the "global registration problem," whereby your goal is to ensure that some
set of classes (or objects or modules or functions, whatever) have all
registered themselves with some global object before main starts, and there
is no single place in the program that knows about all the things to be
registered.

The approach you seem to describe works only if all the static KnownBlock
object are initialized prior to the execution of main, and in fact this is
the case with many compilers, but the ARM does not guarantee that it will
take place.  What the ARM guarantees is that static objects are initialized
before anything *in the same translation unit* is used.  (I'm playing a
little loose with the rules here, but that's the gist of the matter.)  So
the only way to ensure that all the classes are registered is for the
translation unit that contains main to #include all header files that
contain the class declaration for a class to be registered.

This doesn't sound so bad, but bear in mind that I might later add a new
translation unit containing a new class that needs to be registered, but I
might forget to add the #include directive to main, and suddenly my program
might mysteriously fail.

However, perhaps I've misunderstood your design, because the scheme I'm
used to depends on static objects in the .h file, not in the implementation
file, and you say your static objects go in the implementation files.  If
that's the case, how do you know that *any* of your static objects (much
less all of them) are initialized before main is called?

Scott

-------------------------------------------------------------------------------
What do you say to a convicted felon in Providence?  "Hello, Mr. Mayor."




Author: jbuck@forney.berkeley.edu (Joe Buck)
Date: 19 Sep 1992 03:08:03 GMT
Raw View
In article <1992Sep19.015106.10252@cs.brown.edu> sdm@cs.brown.edu (Scott Meyers) writes:
>I'm not convinced.  This sounds a lot like it's an instance of what I call
>the "global registration problem," whereby your goal is to ensure that some
>set of classes (or objects or modules or functions, whatever) have all
>registered themselves with some global object before main starts, and there
>is no single place in the program that knows about all the things to be
>registered.

Yes, it is a solution to the problem, and I can demonstrate that it works
under a variety of OS's with two different compilers.  The design preceded
the publication of the ARM.

>The approach you seem to describe works only if all the static KnownBlock
>object are initialized prior to the execution of main, and in fact this is
>the case with many compilers, but the ARM does not guarantee that it will
>take place.  What the ARM guarantees is that static objects are initialized
>before anything *in the same translation unit* is used.

I'm willing to grant that if you're a language lawyer, this scheme is not
guaranteed to work.  Unless someone can show me a scheme that can make it
work, in that a new class can be added to the system without having any
module that has a master list of all classes (anathema to an extendable
system), I consider this a flaw in the language specification.

However, since the Ptolemy scheme already requires system-dependent code
to perform the incremental linking, if I encountered a compiler that
required something else, I'd add it.

>(I'm playing a
>little loose with the rules here, but that's the gist of the matter.)  So
>the only way to ensure that all the classes are registered is for the
>translation unit that contains main to #include all header files that
>contain the class declaration for a class to be registered.

As I said, this is a master list, and I consider this as evil as a switch
statement that switches on the type.

>This doesn't sound so bad, but bear in mind that I might later add a new
>translation unit containing a new class that needs to be registered, but I
>might forget to add the #include directive to main, and suddenly my program
>might mysteriously fail.

Exactly.

>However, perhaps I've misunderstood your design, because the scheme I'm
>used to depends on static objects in the .h file, not in the implementation
>file, and you say your static objects go in the implementation files.  If
>that's the case, how do you know that *any* of your static objects (much
>less all of them) are initialized before main is called?

Because real compilers call the constructors before main is called.  If
someone gave me one that didn't, I'd add a new startup module.  If the ARM
rule makes something impossible to implement, but I'm assigned to build it
anyway, I'll manage somehow.
--
Joe Buck jbuck@ohm.berkeley.edu




Author: adk@Warren.MENTORG.COM (Ajay Kamdar)
Date: Mon, 21 Sep 1992 17:13:51 GMT
Raw View
In article <1992Sep19.015106.10252@cs.brown.edu> sdm@cs.brown.edu (Scott Meyers) writes:
>
>I'm not convinced.  This sounds a lot like it's an instance of what I call
>the "global registration problem," whereby your goal is to ensure that some
>set of classes (or objects or modules or functions, whatever) have all
>registered themselves with some global object before main starts, and there
>is no single place in the program that knows about all the things to be
>registered.
>
>The approach you seem to describe works only if all the static KnownBlock
>object are initialized prior to the execution of main, and in fact this is
>the case with many compilers, but the ARM does not guarantee that it will
>take place.  What the ARM guarantees is that static objects are initialized
>before anything *in the same translation unit* is used.  (I'm playing a
>little loose with the rules here, but that's the gist of the matter.)  So

It appears to be impossible for compilers to implement the language as
specified by the ARM w.r.t. initialization of static objects. Specificially,
the guarantee that static objects are initialized before a function or object
in the same translation unit is used is not entirely correct. I recently
spent significant effort debugging and reworking my registry of objects
(similar in concept to that described by Joe Buck) because I took this
guarantee too literally. It is my understanding that the Environment
Working Group has been wrestling with this issue and that this statement
will be clarified further. Once the EWG is done with it, one can only
depend upon the static objects in a file being initialized only before the
first use of a function or object "on a path from main", where the first
use of a function or object does not include uses of functions or objects
that occur in the static initialization phase.

>the only way to ensure that all the classes are registered is for the
>translation unit that contains main to #include all header files that
>contain the class declaration for a class to be registered.
>

Yes, that is indeed one of the ways. Though, there are other variants of the
same idea.

>This doesn't sound so bad, but bear in mind that I might later add a new
>translation unit containing a new class that needs to be registered, but I
>might forget to add the #include directive to main, and suddenly my program
>might mysteriously fail.
>

If you are not dynamically adding classes at run time, it is not too
difficult to automate this process of including the appropriate header
files such that new translation units containing a new class automatically
get registered at compile time. I have implemented such a scheme, and it has
worked thus far without any problem.

- Ajay

--
I speak for none but myself.

Ajay Kamdar                               Email : ajay_kamdar@mentorg.com
Mentor Graphics, IC Group (Warren, NJ)    Phone : (908) 580-0102




Author: berczuk@space.mit.edu (Steve Berczuk)
Date: Mon, 21 Sep 1992 20:06:55 GMT
Raw View
> --
>
> Hi,
>
> I want to pass a class name as an argument to a function which creates
> an object
> from that class, since i don't want to write the same function for each class.
> Is this can be achieved in C++? If yes, how ? thanks to respond.
at first glance, it seems what is being mentioned here is discussed in COplien's book Advanced C++ Idioms under the topic of Exemplars... or his chapter
"Emulating Symbolic Language Styles in in C++",

but the solutions that have been posted seem a bit more complicated than those in coplein's book...






Author: laribi@vadier.gr.osf.org (Laribi Youcef)
Date: Thu, 17 Sep 1992 14:12:44 GMT
Raw View
--

Hi,

I want to pass a class name as an argument to a function which creates
an object
from that class, since i don't want to write the same function for each class.
Is this can be achieved in C++? If yes, how ? thanks to respond.

youcef.

--





Author: sakkinen@jyu.fi (Markku Sakkinen)
Date: Fri, 18 Sep 1992 06:06:41 GMT
Raw View
In article <1992Sep17.141244.29693@osf.org> laribi@vadier.gr.osf.org (Laribi Youcef) writes:
>I want to pass a class name as an argument to a function which creates
>an object
>from that class, since i don't want to write the same function for each class.
>Is this can be achieved in C++? If yes, how ? thanks to respond.

No way.
You rather need a language in which classes are themselves fully-fledged
objects, e.g. Smalltalk or CLOS.

----------------------------------------------------------------------
Markku Sakkinen (sakkinen@jytko.jyu.fi)
       SAKKINEN@FINJYU.bitnet (alternative network address)
Department of Computer Science and Information Systems
University of Jyvaskyla (a's with umlauts)
PL 35
SF-40351 Jyvaskyla (umlauts again)
Finland
----------------------------------------------------------------------