Create objects

A

Anarki

Is there a way to create an object by just knowing its type?

i actually work in vb.net, and i believe the concept of OOP remains
nearly same for all OOL :)

consider the following scenario

i pass the type of a class/object as a parameter to a function say
ObjCreator and i need this function to return the object of that class
 
A

Alan Woodland

Anarki said:
Is there a way to create an object by just knowing its type?

i actually work in vb.net, and i believe the concept of OOP remains
nearly same for all OOL :)

consider the following scenario

i pass the type of a class/object as a parameter to a function say
ObjCreator and i need this function to return the object of that class

template <typename T>
T *create() {
return new T;
}

Not sure how useful that really is...

Alan
 
D

David Pratt

Anarki said:
Is there a way to create an object by just knowing its type?

i actually work in vb.net, and i believe the concept of OOP remains
nearly same for all OOL :)

consider the following scenario

i pass the type of a class/object as a parameter to a function say
ObjCreator and i need this function to return the object of that class

I apologize in advance if this sounds, well, arrogant but the best thing you
can do if you want to learn C++ is to forget everything you learned about
programming in VB and start over from scratch in C++. Take it from someone
who has done both; C++ doesn't work the same at all, and the terminology
is different as well. OOP as implemented by VB does not transfer over to
C++ very well, and a "Class" in VB is not the same as a class in C++.
In C++, there would be no need for a creator function; you just create
like so:
TClass *NewClass = new TClass; // bada bing, bada bang, bada boom, its
done
Also, there isn't really an effective way to pass "Types" as
parameters at run time in C++ such that you can "create it" , but there is
way to do so at compile
time through templating.

Now, if you are talking about creating a class factory for ActiveX
objects (and I would bet you are), that's a horse of a different color.
Haven't done much ActiveX programming, and this would not be the appropriate
forum for that discussion anyway. I would try
microsoft.public.activex.controls or microsoft.public.vc.activex.templatelib
if this is the case
 
G

g3rc4n

Is there a way to create an object by just knowing its type?

i actually work in vb.net, and i believe the concept of OOP remains
nearly same for all OOL  :)

consider the following scenario

 i pass the type of a class/object as a parameter to a function say
ObjCreator and i need this function to return the object of that class

c++ is statically typed, by the sounds of it you want to do something
like this

void* foo(const std::string& s){
void* temp = new s;
return temp;
}

which you can't do easily, either

void* foo(const std::string& s){
if(s == "int"){
return new int;
else if(s == "string"){
 
G

g3rc4n

Is there a way to create an object by just knowing its type?

i actually work in vb.net, and i believe the concept of OOP remains
nearly same for all OOL  :)

consider the following scenario

 i pass the type of a class/object as a parameter to a function say
ObjCreator and i need this function to return the object of that class

by the sounds of it you want to do this

void* make(const std::string& s){
return new s; // make new objexct of type of string passed
}

but c++ is statically typed

void* make(const std::string& s){
if(s == "int"){
return new int;
}
else if(s == "double"){
return new double;
}
else{
throw error();
}
}

this is the only way to do it, although you lost type information so
it's all pointless, but someting like this makes sense

base* make(const std::string& s){
if(s == "dira"){
return new dira;
}
else if(s == "dirb"){
return new dirb;
}
else{
throw error();
}
}

this is where meta programming comes in handy ;)
 
G

g3rc4n

Is there a way to create an object by just knowing its type?

i actually work in vb.net, and i believe the concept of OOP remains
nearly same for all OOL  :)

consider the following scenario

 i pass the type of a class/object as a parameter to a function say
ObjCreator and i need this function to return the object of that class

#include <iostream>
#include <string>

struct base{
virtual ~base(){}
virtual void say()=0;
};

struct dira : public base{
void say(){
std::cout << "hi from dira" << std::endl;
}
};
struct dirb : public base{
void say(){
std::cout << "hi from dirb" << std::endl;
}
};

struct maker{
struct error{};
base* make(const std::string& s){
if(s == "dira"){
return new dira;
}
else if(s == "dirb"){
return new dirb;
}
else{
throw error();
}
}
};


struct str_dira{
typedef dira type;
static const std::string str(){
return "dira";
}
};
struct str_dirb{
typedef dirb type;
static const std::string str(){
return "dirb";
}
};

template<class T,
class U>
struct tl_link{
typedef T head;
typedef U tail;
};

struct tl_null{};

template<class TL>
struct makerr : private makerr<typename TL::tail>{
base* make(const std::string& s){
if(s == TL::head::str()){
return new typename TL::head::type;
}
else{
return makerr<typename TL::tail>::make(s);
}
}
};

template<>
struct makerr<tl_null>{
struct error{};
base* make(const std::string&){
throw error();
}
};


int main(){
maker mkr;

base* b = mkr.make("dira");
b->say();
b = mkr.make("dirb");
b->say();

makerr<tl_link<str_dira,tl_link<str_dirb,tl_null> > > mkrr;
b = mkrr.make("dira");
b->say();
b = mkrr.make("dirb");
b->say();
return(0);

}
 
J

James Kanze

Here's just another suggestion: You could try to combine the
envelope/ letter idiom with the factory pattern in your case.
The "envelope" makes it easier to manage the polymorphic
object's life-time.

The envelope/letter pattern is designed so that polymorphic
objects can have value semantics. It's rarely needed, and has
considerable overhead.

In C++, there is no solution for arbitrary types: I would
consider this a feature, however, and not a defect. If all of
the types in question derive from a common base class, it is
rather simple to use a std::map< std::string, Base* (*)() > to
map names to a factory function. (If the types are not
necessarily all known at compile time, it's also possible to
define a mapping type name to filename, with the corresponding
file being dynamically linked in if the name isn't found in the
map. The types still have to derive from a common base,
however, to be useful.)
 
S

SG

The envelope/letter pattern is designed so that polymorphic
objects can have value semantics.  It's rarely needed, and has
considerable overhead.

Just to clearify: By "envelope/letter" I meant a pattern where the
handle object can manage polymorphic objects regardless of having
value or (counted) reference semantics. This is maybe not what you
had in mind.

Here's an example of what I was thinking of. In this case it actually
HAS value semantics but it doesn't have to.

----------8<----------

#include <algorithm>
#include <string>

class LetterBase {
public:
virtual ~LetterBase() {}
virtual double foo(double x) const = 0;
virtual void tweak(double p) = 0;
virtual LetterBase* clone() const = 0;
};

class Envelope {
LetterBase* ptr;
public:
explicit Envelope(LetterBase* p=0) : ptr(p) {}
Envelope(Envelope const& e)
: ptr(e.ptr==0 ? 0 : e.ptr->clone()) {}
~Envelope() {delete ptr;}
void swap(Envelope& with) {std::swap(ptr,with.ptr);}
Envelope& operator=(Envelope e) {swap(e); return *this;}

double foo(double x) const {return ptr->foo(x);}
void tweak(double p) {ptr->tweak(p);}
};

inline void swap(Envelope& a, Envelope& b) {a.swap(b);}

/// creates an Envelope object -- possibly delegating
/// the creation of a LetterBase-derived object according
/// to the given string parameter.
Envelope factory(std::string const& blah);

int main()
{
Envelope e = factory("bar42");
double y1 = e.foo(23.1);
e.tweak(99.0);
double y2 = e.foo(23.1);
}

----------8<----------

This looks pretty much like the code I wrote a couple of weeks ago.
It combines the "compiler firewall" idiom with polymorphism and value
semantics. In my case it was quite useful. The overhead is moderate
and it doesn't affect the performance of typical client code I have in
mind.


Cheers!
SG
 
J

James Kanze

Just to clearify: By "envelope/letter" I meant a pattern where
the handle object can manage polymorphic objects regardless of
having value or (counted) reference semantics. This is maybe
not what you had in mind.

The name letter/envelope comes from Coplien. There's certainly
no problem with it using counted pointers to implement copy on
write, but I think giving it reference semantics changes the
idiom, resulting in something more like the strategy pattern.
(I also can't see the point in having a special class for the
"reference"---reference semantics are largely handled by
pointers, smart or otherwise.)
Here's an example of what I was thinking of. In this case it
actually HAS value semantics but it doesn't have to.

#include <algorithm>
#include <string>
class LetterBase {
public:
virtual ~LetterBase() {}
virtual double foo(double x) const = 0;
virtual void tweak(double p) = 0;
virtual LetterBase* clone() const = 0;
};
class Envelope {
LetterBase* ptr;
public:
explicit Envelope(LetterBase* p=0) : ptr(p) {}
Envelope(Envelope const& e)
: ptr(e.ptr==0 ? 0 : e.ptr->clone()) {}
~Envelope() {delete ptr;}
void swap(Envelope& with) {std::swap(ptr,with.ptr);}
Envelope& operator=(Envelope e) {swap(e); return *this;}

double foo(double x) const {return ptr->foo(x);}
void tweak(double p) {ptr->tweak(p);}
};
inline void swap(Envelope& a, Envelope& b) {a.swap(b);}
/// creates an Envelope object -- possibly delegating
/// the creation of a LetterBase-derived object according
/// to the given string parameter.
Envelope factory(std::string const& blah);
int main()
{
Envelope e = factory("bar42");
double y1 = e.foo(23.1);
e.tweak(99.0);
double y2 = e.foo(23.1);
}
----------8<----------

One of the important aspects in the original Coplien
presentation is that the "letters" derive from the "envelope".
I'm not sure it's an essential point, but it does avoid having
to reproduce the interface twice. Something like:

class Shape
{
public:
Shape( Shape const& other )
: myPtr( other.clone() )
{
}

// Typically, however, we'd have constructors which
// knew how to create their own implementation, so
// client code would never construct a derived.
Shape( Shape* impl )
: myPtr( impl )
{
}

virtual ~Shape()
{
delete myPtr ;
}

virtual void scale( double factor )
{
myPtr->scale( factor ) ;
}
// ...

protected:
Shape()
: myPtr( NULL )
{
}

private:
Shape* myPtr ;
} ;

The only real advantage in this, I think, is that you don't have
to duplicate the interface. You're guaranteed that the
interface seen by the client is identical to the one you derive
from.
This looks pretty much like the code I wrote a couple of weeks
ago. It combines the "compiler firewall" idiom with
polymorphism and value semantics. In my case it was quite
useful. The overhead is moderate and it doesn't affect the
performance of typical client code I have in mind.

Yes. I've used it from time to time. Most of the time,
polymorphism seems to apply to objects which have identity,
which means reference semantics, in which case, I'll just use a
classic hierarchy and pointers (smart or otherwise, depending on
the role of the object in the application). There are also a
fair number of cases where the identity doesn't matter, but the
objects have no mutable state, so I can use reference semantics
just as easily as value---such cases are usually best handled by
a smart pointer (unless you have garbage collection, in which
case a raw pointer works just as well). But every once in a
while, there is a need for true value type with polymorphic
behavior, in which case I use the envelope letter pattern.
Deriving from the envelope, as above, but probably because
that's the way I learned it, more than for any othe reason.
 
S

SG

The name letter/envelope comes from Coplien.

Thank you for the pointer.
There's certainly
no problem with it using counted pointers to implement copy on
write, but I think giving it reference semantics changes the
idiom [...] (I also can't see the point in having a special
class for the "reference"---reference semantics are largely
handled by pointers, smart or otherwise.)

I agree. It's less confusing that way.

Cheers!
SG
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top