DJ_AM_Juicebox
asked on
design bad or good?
Hi,
I'm trying to design a small system that will make growing with dlls easy in the future. Below I made a small example of what I'm trying to accomplish. I have a car interface from which actual cars are derived. A car dealership produces cars with the CarDealership::BuyCar() function. The programmer has to pass an enumerated car type to the dealership to get the actual car type they're interested in buying:
class ICar {
virtual void TurnOn() = 0;
virtual void OpenDoor() = 0;
virtual void GetRegistration() = 0;
};
class Jeep : public ICar {
// implement virtual functions above for a jeep.
};
class Van : public ICar {
// implement virtual functions above for a van.
};
class CarDealership {
ICar* BuyCar(int nCarType)
{
ICar* pNewCar = NULL;
switch (nCarType) {
case TYPE_JEEP;
return new Jeep();
case TYPE_VAN:
return new Van();
}
}
void BringCarInForInspection(IC ar* pCar)
{
pCar->OpenDoor();
pCar->GetRegistration();
}
};
int main()
{
CarDealership dealer;
ICar* pMyCar = dealer.BuyCar(TYPE_JEEP);
pMyCar->OpenDoor();
pMyCar->TurnOn();
dealer.BringCarInForInspec tion(pMyCa r);
}
Now to my understanding as long as the programmer puts all the jeep/van specific code in the separate classes, everything will work well. On the outside, everything will look generic since I'll be using only the interface functions of ICar.
My real question is how can I make the CarDealership::BuyCar() function extensible with dlls? The above design means that if I add a new car type class like 'sedan', I have to recompile my application with the new sedan class and enumeration type. Is it possible to create a dll for each new car type class (always derived from ICar) and load them dynamically at runtime:
ICar* BuyCar(string strPathToCarDLL)
{
ICar* pNewCar = NULL;
// 1) Load dll at passed path?
// 2) Inside the dll, access some creation method which returns the car type that dll defines?
// 3) Return the purchased car type?
LoadDll(strPathToCarDLL);
pNewCar = NewDLL.ProduceSpecificCarT ype();
return pNewCar;
}
I'm not sure how the above could be accomplished.
Thanks
I'm trying to design a small system that will make growing with dlls easy in the future. Below I made a small example of what I'm trying to accomplish. I have a car interface from which actual cars are derived. A car dealership produces cars with the CarDealership::BuyCar() function. The programmer has to pass an enumerated car type to the dealership to get the actual car type they're interested in buying:
class ICar {
virtual void TurnOn() = 0;
virtual void OpenDoor() = 0;
virtual void GetRegistration() = 0;
};
class Jeep : public ICar {
// implement virtual functions above for a jeep.
};
class Van : public ICar {
// implement virtual functions above for a van.
};
class CarDealership {
ICar* BuyCar(int nCarType)
{
ICar* pNewCar = NULL;
switch (nCarType) {
case TYPE_JEEP;
return new Jeep();
case TYPE_VAN:
return new Van();
}
}
void BringCarInForInspection(IC
{
pCar->OpenDoor();
pCar->GetRegistration();
}
};
int main()
{
CarDealership dealer;
ICar* pMyCar = dealer.BuyCar(TYPE_JEEP);
pMyCar->OpenDoor();
pMyCar->TurnOn();
dealer.BringCarInForInspec
}
Now to my understanding as long as the programmer puts all the jeep/van specific code in the separate classes, everything will work well. On the outside, everything will look generic since I'll be using only the interface functions of ICar.
My real question is how can I make the CarDealership::BuyCar() function extensible with dlls? The above design means that if I add a new car type class like 'sedan', I have to recompile my application with the new sedan class and enumeration type. Is it possible to create a dll for each new car type class (always derived from ICar) and load them dynamically at runtime:
ICar* BuyCar(string strPathToCarDLL)
{
ICar* pNewCar = NULL;
// 1) Load dll at passed path?
// 2) Inside the dll, access some creation method which returns the car type that dll defines?
// 3) Return the purchased car type?
LoadDll(strPathToCarDLL);
pNewCar = NewDLL.ProduceSpecificCarT
return pNewCar;
}
I'm not sure how the above could be accomplished.
Thanks
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
BTW, that concept is similar - yet way more simplyfied - to the one that COM uses.
ASKER
sounds good, I'll give it a try, thanks a lot.
>>>> Is it possible to create a dll for each new car type class
>>>> (always derived from ICar) and load them dynamically at runtime:
Of course it is possible to have a derived class in a dll. But you can not access it if the header was unknown in the calling executable. Also polymorphism doesn't work well beyond dll boundaries. You could create a object in the dll thus getting a virtual table which contains all pointers of the class tree. But if you would use that pointer in the calling executable, it wouldn't find the virtual function code defined in the dll cause each executable has it own pointers. So, it would crash and there is no way out in C++.
The COM way jkr described doesn't work with derived classes that are unknown in the baseclass. In COM it works by means of C function pointers and many (proprietary) enhancements MS had added over years to the COM interface. The main purpose of COM is not to enhance a C++ class hierarchy by loading derived objects dynamically but to *use* a exported functionality located in a different executable. It actually isn't C++ but pure C with a C++ wrapper. I have only small doubts that it is possibly somehow to realize your requirements via COM or a COM-like mechanism - cause it is a mighty mechanism- but I am rather sure that it is not worth the efforts for your requirements.
A different thing is if you would not derive from ICar but load the supported types from somewhere, say from a database. Then, you could 'customize' your executable by database triggers or by loading additional dlls dynamically depending on theh car type (or car name) and call a predefined 'customize' function via function pointer. The results were returned in a struct which needs to be known by both executables what most likely isn't a problem. You also can exchange a XML what can make the results dynamically as well.
Regards, Alex
>>>> (always derived from ICar) and load them dynamically at runtime:
Of course it is possible to have a derived class in a dll. But you can not access it if the header was unknown in the calling executable. Also polymorphism doesn't work well beyond dll boundaries. You could create a object in the dll thus getting a virtual table which contains all pointers of the class tree. But if you would use that pointer in the calling executable, it wouldn't find the virtual function code defined in the dll cause each executable has it own pointers. So, it would crash and there is no way out in C++.
The COM way jkr described doesn't work with derived classes that are unknown in the baseclass. In COM it works by means of C function pointers and many (proprietary) enhancements MS had added over years to the COM interface. The main purpose of COM is not to enhance a C++ class hierarchy by loading derived objects dynamically but to *use* a exported functionality located in a different executable. It actually isn't C++ but pure C with a C++ wrapper. I have only small doubts that it is possibly somehow to realize your requirements via COM or a COM-like mechanism - cause it is a mighty mechanism- but I am rather sure that it is not worth the efforts for your requirements.
A different thing is if you would not derive from ICar but load the supported types from somewhere, say from a database. Then, you could 'customize' your executable by database triggers or by loading additional dlls dynamically depending on theh car type (or car name) and call a predefined 'customize' function via function pointer. The results were returned in a struct which needs to be known by both executables what most likely isn't a problem. You also can exchange a XML what can make the results dynamically as well.
Regards, Alex
>>The COM way jkr described doesn't work with derived classes that are
>>unknown in the baseclass.
That's not correct. Nowhere in the above is a linkage to something the base class needs to know about derived classes. If you are thinking about the symbolic constant names - they are only there for demostration purposes and don't play an role when read from e.g. the registry.
>>unknown in the baseclass.
That's not correct. Nowhere in the above is a linkage to something the base class needs to know about derived classes. If you are thinking about the symbolic constant names - they are only there for demostration purposes and don't play an role when read from e.g. the registry.
>>>> Nowhere in the above is a linkage to something
>>>> the base class needs to know about derived classes.
Yes, I didn't say that the above code wouldn't work, but I am pretty sure that calling a virtual function by using a baseclass pointer doesn't work via dll boundaries. That would mean that you could access the 'derived' classes only via their COM interface what is by C function pointer and not by C++ polymorphism.
Again, I didn't say the concept is bad but it isn't a solution for the requirement to implement derived classes and their virtual overloads in a separate dll which can be loaded dynamically and called by the executable. And it is not possible to add a new derived class where the baseclass doesn't know of beside you would implement something like a factory which isn't part of the above concept til now.
>>>> the base class needs to know about derived classes.
Yes, I didn't say that the above code wouldn't work, but I am pretty sure that calling a virtual function by using a baseclass pointer doesn't work via dll boundaries. That would mean that you could access the 'derived' classes only via their COM interface what is by C function pointer and not by C++ polymorphism.
Again, I didn't say the concept is bad but it isn't a solution for the requirement to implement derived classes and their virtual overloads in a separate dll which can be loaded dynamically and called by the executable. And it is not possible to add a new derived class where the baseclass doesn't know of beside you would implement something like a factory which isn't part of the above concept til now.
I'd suggest a way that's independent of COM and DLL's altogether. The whole world is not Microsoft. Even they are backing away from COM.
Since this looks like a relatively low-crunching application, you might consider an architecture with much more flexibility than a compiled language can provide. Say keep the data in a SQL database and use a very flexible and extensible language, say Perl. A whole lot of cant-get-there-from here and portability problems go away.
Since this looks like a relatively low-crunching application, you might consider an architecture with much more flexibility than a compiled language can provide. Say keep the data in a SQL database and use a very flexible and extensible language, say Perl. A whole lot of cant-get-there-from here and portability problems go away.
>>>> I'd suggest a way that's independent of COM and DLL's altogether
You are suggesting a way that is independent of C++ as well. I don't mind if you prefer PERL over C++ but maybe the PERL TA would be the better forum to throw it in as a recommendation.
>>>> this looks like a relatively low-crunching application
Don't think so. Deriving classes in C++ is the main benefit of a OOP. And it is a legitimate requirement to have the implementation of a derived class in a different library than the baseclass. However, the normal design for that, is to put the baseclass implementation into a own library (shared or not) and the derived classes link against that library. An application which uses any of the objects in the derived classes would link against all these libraries. You can use a factory design in that application if you want to implement it generically, i. e. if the application must not know which objects it has to handle. It could read the 'names' or 'types' from a database and create the objects via function pointer. The function pointer was provided by each derived class which registered a static create function in a shared 'factory map'. The 'factory map' maps a class name, e. g. 'JEEP' to the create function that can create 'JEEP' objects. All that is within the normal functionality of C++ and is safe because it is compiled. And the only flaw is that you can't add new derived classes by dynamically loading a new dll. But that is more a issue of shared libraries rather than a C++ issue.
Regards, Alex
You are suggesting a way that is independent of C++ as well. I don't mind if you prefer PERL over C++ but maybe the PERL TA would be the better forum to throw it in as a recommendation.
>>>> this looks like a relatively low-crunching application
Don't think so. Deriving classes in C++ is the main benefit of a OOP. And it is a legitimate requirement to have the implementation of a derived class in a different library than the baseclass. However, the normal design for that, is to put the baseclass implementation into a own library (shared or not) and the derived classes link against that library. An application which uses any of the objects in the derived classes would link against all these libraries. You can use a factory design in that application if you want to implement it generically, i. e. if the application must not know which objects it has to handle. It could read the 'names' or 'types' from a database and create the objects via function pointer. The function pointer was provided by each derived class which registered a static create function in a shared 'factory map'. The 'factory map' maps a class name, e. g. 'JEEP' to the create function that can create 'JEEP' objects. All that is within the normal functionality of C++ and is safe because it is compiled. And the only flaw is that you can't add new derived classes by dynamically loading a new dll. But that is more a issue of shared libraries rather than a C++ issue.
Regards, Alex