473,385 Members | 1,622 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

plugin system implementation : dynamic_cast through invisible classes

Hello,

I've been writing a program, which works with some special type of files : namely files, containing "pages". Since there are several formats for that type of things, and I'm not likely to know all, I wanted to make the program extensible through external plugins (in shared libraries).

I decided that a plugin will return a pointer to a "general file" object, which, in turn, will contain some "general pages". There are several distinct possible types of pages, so those are declared as interfaces. So (in principle) a plugin would subclass "general page", and then subclass that one with specific intefaces, like:
Expand|Select|Wrap|Line Numbers
  1. class SpecialPage : public GeneralPage;
  2. class SpecialPageType1 : public SpecialPage, public Type1;
  3. class SpecialPageType2 : public SpecialPage, public Type2;
  4.  
The GeneralPage contains information about the page type, but Type1 and Type2 are separate classes, to allow for the above-mentioned scheme without the "diamond" inheritance.

But now I can't make this thing work, since the following cast produces NULL
Expand|Select|Wrap|Line Numbers
  1. GeneralPage * page = getGeneralPage(...);
  2.  // The function actually returns a dynamic_cast<GeneralPage*>(SpecialPage*)
  3. if (page->type() == type1)
  4.  Type1 * page1 = dynamic_cast<Type1*>(page);
  5.  
The type seems to exists only in the plugin itself, and I don't seem to be able to export that one too (I'm using gcc).

So, question: am I missing something, or it is indeed not possible, and I should rethink the design?
Oct 10 '07 #1
5 2718
weaknessforcats
9,208 Expert Mod 8TB
GeneralPage * page = getGeneralPage(...);
// The function actually returns a dynamic_cast<GeneralPage*>(SpecialPage*)
if (page->type() == type1)
Type1 * page1 = dynamic_cast<Type1*>(page);
First things first: When you cast in C++ you are either calling a relic C function with a void* argument or your C++ design is weak.

Second: dynamic_cast requires RTTI which in turn requires the compiler to keep a database on every object with virtual functions so it knows what the real type is. This is very expensive and I advise against using this thing unless you are firefighting.

Third: dynamic cast only works with classes that have virtual functions. Otherwise, you already know the type.

Fourth: dynamic_cast will not permit unsafe casts. That is, you can cast a pointer to a derived type to a pointer to a base type but not the other way. Going the other way, the base pointer would be casted to a type that has more data and methods than the base object. Using those methods would then cause a crash. Hence, when you cast from a base pointer to a derived pointer, you always get NULL.

Have you considered:
Expand|Select|Wrap|Line Numbers
  1. class class SpecialPageType1 :public Type1
  2. {
  3.     private:
  4.         General* theSpecialPage;
  5. };
  6.  
where SpecialPage : public GeneralPage ??

You could create a SpecialPage object and reference it in your SpecialPageType1 class.

If this is to be object-oriented, then all methods you execute using a SpecialPageType1 object must be Type1 methods:
Expand|Select|Wrap|Line Numbers
  1. GeneralPage* g = new SpecialPage;
  2. Type1* obj = new SpecialPageType1(g);
  3.  
and now you need no casts at all.
Oct 10 '07 #2
RRick
463 Expert 256MB
Hence, when you cast from a base pointer to a derived pointer, you always get NULL.
That's not always true. If you have a base pointer that actually points to a derived class, then you use dynamic cast to convert from a base pointer to a derived pointer. For more info, see http://en.wikipedia.org/wiki/Dynamic_cast

Dynamic_cast can deal with multiple inheritance, but there are several caveats. The "diamond" structure you talked about is one. Maybe there is a problem with interfaces, but I can't say for sure (and I don't see why).

The base class definitely needs a virtual method, and many sources stress making the base class destructor virtual. This kills two birds with one stone. You get RTTI, and you solve the splitting issues with destructors.
Oct 10 '07 #3
weaknessforcats
9,208 Expert Mod 8TB
That's not always true. If you have a base pointer that actually points to a derived class,
Yes. I guess I wasn't clear about that. I was thinking of a base pointer to a base object.
Oct 11 '07 #4
Dynamic_cast can deal with multiple inheritance, but there are several caveats. The "diamond" structure you talked about is one. Maybe there is a problem with interfaces, but I can't say for sure (and I don't see why).

The base class definitely needs a virtual method, and many sources stress making the base class destructor virtual. This kills two birds with one stone. You get RTTI, and you solve the splitting issues with destructors.
The real problem in this case seems to be the shared library boundary. dynamic_cast fails because the typeid is unknown to it. If you compile the "SpecialPage" classes in, everything works. I tried to follow the quidelines GCC has in it's FAQ about shared libraries, but it doesn't help.

I came up with a (really dirty) workaround, where the GeneralPage class has a virtual abstract function, casting the typed base into void, that can be afterwards reinterpreted in the main program, if the page type is known. The function has, of course, to be implemented in each SpecialPageType# class. The solution works, although I don't like it too much.

Is there really no way to get RTTI information across shared library boundaries?
Oct 11 '07 #5
Have you considered:
Expand|Select|Wrap|Line Numbers
  1. class class SpecialPageType1 :public Type1
  2. {
  3.     private:
  4.         General* theSpecialPage;
  5. };
  6.  
where SpecialPage : public GeneralPage ??

You could create a SpecialPage object and reference it in your SpecialPageType1 class.
This, unfortunately, doesn't allow me to create an array of pages, independently of their type. And if I create several arrays, I'll have poor compatibility, in case I discover later that there can be one more page type I didn't think of.

And solving the array problem by making GeneralPage a base of Type#, either leads to duplicating the common code for all SpecialPage types, or to diamond inheritance.

Maybe I'm missing some other obvious solution... I will be happy to know about such a design.
Oct 11 '07 #6

Sign in to post your reply or Sign up for a free account.

Similar topics

7
by: Reinhold Birkenfeld | last post by:
Hello, another philosophical question: How would you implement a plugin system (for a web-based application)? Conditions are: - One plugin can have one or many "parts" (or "subplugins", or...
8
by: Zheng Da | last post by:
I don't know where should I ask the question, so send the email to this group. I choose this group, because I want to write the program with c++ :) I want to write a program which support...
2
by: Rudolf | last post by:
Dear NG, I want to create a Plugin System in C# (WinForms). Has anybody experience about this, tips, tricks, or any links. Thank you very much The DotNetJunkie
3
by: Roger Boesch | last post by:
Im currently working on a plugin architectur for a software product written in c# and have found the following problem: Project a) Application, Application with all classes used in this app ...
18
by: bsruth | last post by:
I tried for an hour to find some reference to concrete information on why this particular inheritance implementation is a bad idea, but couldn't. So I'm sorry if this has been answered before....
15
by: Grizlyk | last post by:
Hello. Returning to question of manual class type identification, tell me, for ordinary inheritance is C++ garantee that dynamic_cast<Derived*>(Base*) can be implemented similarly to ...
7
by: WTH | last post by:
I am now aware (I am primarily a C++ developer) that in C# if you reference the same interface from the same file in two different projects the types are actually incompatible. I found this out...
25
by: lovecreatesbea... | last post by:
Suppose I have the following three classes, GrandBase <-- Base <-- Child <-- GrandChild The following cast expression holds true only if pBase points object of type of ``Child'' or...
0
by: =?ISO-8859-1?Q?J=FCrgen_B=F6hm?= | last post by:
Hello, (I already posted this at comp.lang.c++.moderated, but received no answers, maybe it is better placed here?): to implement a little symbolic computation system, dealing with...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.