Virtual Parameter Passing

This is more a question than a statement...

I am looking for a particular C++ programming idiom to help me in my current project. I wonder if other people ran into this problem before.

I have an abstract class. The class has a method to create another object of that class by combining some arbitrary information passed as arguments to the method and information present in the object on which the creation method is called (think creating a child under a tree node). The problem is, the nature of parameters to be used is not known at the abstract base class level. I can't limit what's to be passed to the creation method. The closest thing I have to a solution is to pass a reference to another object as a parameter. Then the actual derived class that implements creation method will cast it up to the derived-class-specific data class and use the data. This is just a wee bit better than passing void *.

Has anyone ran into this situation before? It smells of a pattern to me. In Smalltalk, that wouldn't even be a problem: the data object would either respond or not respond to certain messages. C++'s static types make us use a cast that is inherently unreliable.

-- ArkadiyBelousov

The obvious but not available solution is: MultipleDispatch and the usual route then is probably to use some VisitorPattern to emulate this.


C++'s static types make you aware of a potential type-compatibility problem, rather than just silently "not responding" to the message (if that's indeed what happens; I am Smalltalk-ignorant). Isn't that a good thing? -- MikeSmith


The problem is, I _do_ need different things passed to different methods. I have to go around static type checking to achieve that.

Try boost::any or boost::variant. --ArneVogel


The C idiom that comes to mind is VarArgs? - the same technology that makes printf work: You have to fix the type of the first parameter, but from there on, it can be fully data driven. (If all else fails, make the first parameter a usless dummy parameter.) The abstract base class defines "SomeType? copy(int atLeastOneBaseClassParm, ...);" The base class will pass a parameter of type "va_list" to the concrete sub class (unless copy is a virtual function).

To use VarArgs?, some code somewhere has to know what values of what types were really pushed on the stack. The "printf" family of functions uses the format string ("%s, %d, etc.") for this. Your concrete child class will know what parameters to expect and just hard code all the va_arg calls. You need to look at VarArgs?, "#include <stdarg.h>", va_list, va_arg, va_start and va_end. -- JeffGrigg

Be aware that passing non-POD types in variable-length argument lists is undefined. Pointers to them are fine. (POD types are essentially those that you could write an "easy" equivalent to in C. No constructor or destructor, no virtual functions, and no non-POD members. Non-virtual member functions are fine.)


Just bite the bullet and go to a properties object that is passed in to the constructor or a factory create method. This way you can pass in anything, it's extensible, printable, and is composable from multiple sources (file, containers, application environment, etc). -- AnonymousDonor


So far, I see two distinct solutions here: cast (in some shape, vararg solution is also a cast) or property object. While I don't think cast is a pattern, a property object actually is. A bit heavy-weight, but it seems to be the way to go.

-- ArkadiyBelousov


How about passing objects which can create an object of your class instead of a list of parameters. It could look something like this:

class B;

class BCreator { public:

  virtual B * CreateB()=0;  
};

class B {

  B * CreateB(BCreator & p) {return p.CreateB();}
};

class BCreatorInt: public BCreator { public:

  BCreatorInt(int val):val_(val){}
  virtual B * CreateB() {return new B(val_);}
private:
  int val_;
};

-- Lewis Thomas


Since each subclass signature is different, polymorphism isn't your donut. Instead, use a protected constructor in the base class to partially construct the class.

class Base {
...
protected:
Base( Base *pParent );
};

class Subclass : public Base { public: Subclass( int extra, double parameters ) : Base(this) { do something interesting with extra parameters. } ... };

If you're feeling especially complicated, you can use the NamedConstructorIdiom?. -- SunirShah


You can get similar behaviour to what you describe you get from Small Talk using the following. However, I don't think this is good code, maybe if you could explain your example a bit better, somebody could offer you a better solution. It sounds a bit to me like you're trying to make something abstract that just is inherently not abstract. - Scott Langham

==== Node.h ====

class CreationArgs {

virtual ~CreationArgs() {}
};

class Node {

virtual ~Node() {}
Node* CreateChild( CreationArgs& args ) = 0;
};

==== FolderNode.h ====

class FolderCreationArgs { public:

std::string m_folderName;
};

class FolderNode {

std::string m_folderName;
std::string m_parentName;
public:
FolderNode( FolderCreationArgs& args, std::string& parentName );
Node* CreateChild( CreationArgs& args );
};

==== FolderNode.cpp ====

FolderName::FolderName( FolderCreationArgs& args, std::string& parentName )

  : m_folderName( args.m_folderName ), m_parentName(parentName)
{ }

Node* FolderName::CreateChild( CreationArgs& args ) {

FolderCreationArgs* args = dynamic_cast<FolderCreationArgs*>(*args) )
if( !args )
return NULL;

FolderNode* node = new FolderNode( *args, m_folderName );
}


See also: ArrayOfConst, IncludeFileParametricPolymorphism


CeePlusPlusIdioms CategoryCpp


EditText of this page (last edited April 5, 2008) or FindPage with title or text search