Returning another class' function value
-
On 18/02/2013 at 10:54, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Then I'm right back to square one. Not being able to up share my tag's class members with a previous GeDialog's class.Which is why I say that working in these C4D plugins is sometimes different than working in Raw C++. Based
on your post. It sounds like sharing two SDK classes is better done by
allocation. And not by trying to break down the OOP class structure
between them.Since this has nothing to do with the OP. I better stop posting here and return control back to WickedP.I apologize for hijacking your thread WP.Thanks for the information guys. I'm always learning new things from you guys.-ScottAYou can definitely do that (not easily across different plugins DLLs tho).
What you are missing is a cast.
And you also have to call GetNodeData() on the tag. You plugin tag is not derived from C4DAtom (like BaseTag) but from NodeData.
The NodeData is attached to the GeListNode (which is derived from C4DAtom ).To safely get the pointer to your plugins node data from a BaseTag:
BaseTag* yourTag = BaseTag::Alloc(YOUR_PLUGIN_ID);//(where ever you may be getting it from, allocate?) YourPluginClass* yourPlugin = NULL; if(yourTag != NULL && yourTag->GetType() == YOUR_PLUGIN_ID) { yourPlugin = static_cast<YourPluginClass*>(yourTag->GetNodeData()); }
edit: fixed some stuff
-
On 18/02/2013 at 11:13, xxxxxxxx wrote:
Regarding forwards declaration of classes. You can only forwards declare them when all you do after forwards declaration is declaring a pointer. As soon as you access it, you need to include the header file.
Examples...
Wrong:
class BaseTag; class class1 { public: BaseTag* tag; // forwards declaration is fine, since we are just declaring the a pinter. void doStuff() { LONG type = tag->GetType(); // Compiler error. "Undefined class BaseTag". When using the pointer the compiler needs to know more about the class. } };
Right:
#include <c4d.h> // Inlcudes "c4d_basetag.h" class class1 { public: BaseTag* tag; void doStuff() { LONG type = tag->GetType(); // No compiler error. The compiler knows the class. } };
-
On 18/02/2013 at 12:58, xxxxxxxx wrote:
Thanks fused.
But I'm not sure how to write your casting code. I don't know what "YourPluginClass" supposed to be standing for?Here's an example of a dialog class with a tag class below it. And trying to share one of the tag's class members with the GeDialog class above it:
#define DIALOG_PLUGIN_ID 1000001 //The GeDialog plugin's ID #define TAG_PLUGIN_ID 1000002 //The Tag plugin's ID //-------- The GeDialog plugin --------------------// //-------------------------------------------------// class MyDialog : public GeDialog { public: MyDialog(); BaseTag* tag; void doStuff() { LONG type = tag->GetType(); GePrint(LongToString(type)); } //GeDialog Overrides Bool CreateLayout(); Bool InitValues(); Bool Command(LONG id, const BaseContainer& data); Bool CoreMessage(LONG id, const BaseContainer& data); }; MyDialog::MyDialog() //The GeDialog's constructor { GeDialog(); tag = BaseTag::Alloc(TAG_PLUGIN_ID); MyDialog* MyDialog = NULL; if(tag != NULL && tag->GetType() == TAG_PLUGIN_ID) { //yourPlugin = static_cast<YourPluginClass*>(tag->GetNodeData()); //<----Not sure how to write this..What does "YourPluginClass" stand for? MyDialog = static_cast<MyDialog*>(tag->GetNodeData()); //<-------wrong! MyDialog = static_cast<GeDialog*>(tag->GetNodeData()); //<-------wrong! } } ... etc. //-------- The tag plugin -------------------------// //-------------------------------------------------// class StorageTag : public TagData { public: static NodeData* Alloc() { return gNew StorageTag; } LONG imagecount; //<---I want to share this class member so I can use it inside the MyDialog class //Overrides StorageTag(); Bool Init(GeListNode* node); void Free(GeListNode* node); Bool Read(GeListNode* node, HyperFile* file, LONG level); Bool Write(GeListNode* node, HyperFile* file); Bool Message(GeListNode* node, LONG id, void* msgData); }; ...etc.
-ScottA
-
On 18/02/2013 at 13:14, xxxxxxxx wrote:
YourPluginClass stands for the class derived from NodeData (from which TagData, ObjectData, etc are dervied). In your example that would be StorageTag.
tag = BaseTag::Alloc(TAG_PLUGIN_ID); StorageTag* MyTag = NULL; if(tag != NULL && tag->GetType() == TAG_PLUGIN_ID) { MyTag = static_cast<StorageTag*>(tag->GetNodeData()); }
-
On 18/02/2013 at 13:33, xxxxxxxx wrote:
Ok thanks.
Fixed that. But still running into undeclared errors.MyDialog::MyDialog() { GeDialog(); tag = BaseTag::Alloc(TAG_PLUGIN_ID); StorageTag* MyTag = NULL; //<------------ undeclared identifier :-( if(tag != NULL && tag->GetType() == TAG_PLUGIN_ID) { MyTag = static_cast<StorageTag*>(tag->GetNodeData()); } }
-ScottA
-
On 18/02/2013 at 13:42, xxxxxxxx wrote:
You've missed the forward-declaration, then.
-
On 18/02/2013 at 13:47, xxxxxxxx wrote:
Oh, you need to declare StorageTag first and MyDialog.
So:
#define DIALOG_PLUGIN_ID 1000001 //The GeDialog plugin's ID #define TAG_PLUGIN_ID 1000002 //The Tag plugin's ID //-------- The tag plugin -------------------------// //-------------------------------------------------// class StorageTag : public TagData { ... }; //-------- The GeDialog plugin --------------------// //-------------------------------------------------// class MyDialog : public GeDialog { ... };
The other option would be to move each classes declaration/definition into it's own h/cpp files and have them the MyDialog file include/forwards declare the StorageTag (don't forget "#pragma once"/include guards).
-
On 18/02/2013 at 13:50, xxxxxxxx wrote:
Originally posted by xxxxxxxx
You've missed the forward-declaration, then.
Forwards declaration will not work here unless he splits the class declaration and function definitions into h and cpp files (as the actual function definition is using the forwards declared class).
-
On 18/02/2013 at 13:54, xxxxxxxx wrote:
Moving the tag's class above the GeDialog class defeats the whole purpose of what I'm trying to do.
Sharing downwards is fairly simple.
But sharing upwards is proving to be very, very difficult.-ScottA
-
On 18/02/2013 at 14:05, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Moving the tag's class above the GeDialog class defeats the whole purpose of what I'm trying to do.Sharing downwards is fairly simple.But sharing upwards is proving to be very, very difficult.-ScottA
edit: actually you *could* move MyDialog::MyDialog() below the declaration of StorageTag. Declare both classes first, then provide the implementations. But that would then sum up about all your available options.
No it's not, what you are trying is simply impossible with c++
Solution: One class, one .h and one .cpp file:
MyDialog.h:
#pragma once #include <c4d.h> #define DIALOG_PLUGIN_ID 1000001 //The GeDialog plugin's ID //-------- The GeDialog plugin --------------------// //-------------------------------------------------// class MyDialog : public GeDialog { public: MyDialog(); BaseTag* tag; void doStuff() { LONG type = tag->GetType(); GePrint(LongToString(type)); } //GeDialog Overrides Bool CreateLayout(); Bool InitValues(); Bool Command(LONG id, const BaseContainer& data); Bool CoreMessage(LONG id, const BaseContainer& data); };
MyDialog.cpp:
#include "MyDialog.h" #include "StorageTag.h" // Storage tag used, need to include MyDialog::MyDialog() //The GeDialog's constructor { GeDialog(); tag = BaseTag::Alloc(TAG_PLUGIN_ID); StorageTag* MyTag = NULL; if(tag != NULL && tag->GetType() == TAG_PLUGIN_ID) { MyTag = static_cast<StorageTag*>(tag->GetNodeData()); } } //Register function here. ... etc.
StorageTag.h:
#pragma once #include <c4d.h> #define TAG_PLUGIN_ID 1000002 //The Tag plugin's ID //-------- The tag plugin -------------------------// //-------------------------------------------------// class StorageTag : public TagData { public: static NodeData* Alloc(); LONG imagecount; //<---I want to share this class member so I can use it inside the MyDialog class //Overrides StorageTag(); Bool Init(GeListNode* node); void Free(GeListNode* node); Bool Read(GeListNode* node, HyperFile* file, LONG level); Bool Write(GeListNode* node, HyperFile* file); Bool Message(GeListNode* node, LONG id, void* msgData); };
StorageTag.cpp:
#include "StorageTag.h" NodeData* StorageTag::Alloc() { return gNew StorageTag; } //Register function here. ...etc.
-
On 18/02/2013 at 14:31, xxxxxxxx wrote:
WickedP.
Do you still have questions about your code?
I've completely stolen your thread and I want to give it back to you.-ScottA
-
On 18/02/2013 at 15:24, xxxxxxxx wrote:
lol
-
On 18/02/2013 at 17:59, xxxxxxxx wrote:
Originally posted by xxxxxxxx
WickedP.
Do you still have questions about your code?
I've completely stolen your thread and I want to give it back to you.-ScottA
Ha That's no troubles at all Scott! I'm enjoying the conversation. I know next to nothing about C++ so it's all a learning experience from my perspective - it'll all help somewhere along the line I'm sure!
I'm actually away on holiday at the moment so it can be a bit difficult at times to log on. I'm currently in Cambodia's south, heading to the north in half an hour or so. So I'm trying to do what I can in the spare moments I have. I'm quite excited about my plugin, hence why I bombared the forums a little at times. Just excited to try and push further with it and get it out there! Would love to show you guys what I have at some stage. It's not a world stopper but... I think it'll have some use. Certainly for myself it will.
RE: sharing a functions return downwards - I'm still having troubles getting anything other than an empty return. I had wondered about using multiple .h files - perhaps that's a better way for me at this stage? But haven't had a chance to try that yet. Will keep playing around.
Cheers all,
WP. -
On 19/02/2013 at 10:10, xxxxxxxx wrote:
Going back to the examples you posted earlier.
I noticed that you are in the habit of using the type specifier on your class member variables when assigning values to them.
That will re-declare the variable in a different place. And make it a local variable that isn't globally available to your other methods like a class variable.
That's probably why you keep getting no return values.Once you've declared a class member variable: String myString;
Don't use the "String" type specifier on it when you go and assign a value to it later on.
Just use the variable's name: myString = "HelloWorld".-ScottA
-
On 20/02/2013 at 03:38, xxxxxxxx wrote:
Hi Scott,
I've just had a peek at my code and this particular string is declared without the type. It GePrints fine from the function if I run it from within the class, but when the bottom class runs it the prints (even when within the function itself) are empty.Not sure what else I can do.
WP. -
On 20/02/2013 at 03:49, xxxxxxxx wrote:
Not sure what else I can do.
Post compilable code that does not work for you, and some one here may be will find the solution -
On 20/02/2013 at 05:06, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Going back to the examples you posted earlier.
I noticed that you are in the habit of using the type specifier on your class member variables when assigning values to them.
That will re-declare the variable in a different place. And make it a local variable that isn't globally available to your other methods like a class variable.
That's probably why you keep getting no return values.Once you've declared a class member variable: String myString;
Don't use the "String" type specifier on it when you go and assign a value to it later on.
Just use the variable's name: myString = "HelloWorld".Wrong, it's simply class-construction.
String str = "outter"; /* new scope */ { str = String("inner"); } GePrint(str);
String str = "outter"; /* new scope */ { String str = String("inner"); } GePrint(str);
-Niklas
-
On 20/02/2013 at 05:32, xxxxxxxx wrote:
Firs example is a bit confusion.
Why not use the same way to assign?
But this is a more code style question.String str = String("outter"); /* new scope */ { str = String("inner"); } GePrint(str);
Second is error-prone and should not be used!
-
On 20/02/2013 at 05:45, xxxxxxxx wrote:
_ >>> Why not use the same way to assign?_
> I wanted to demonstrate that there is no difference because of the implementation of the String
>
> class. I don't know if the String class explicitly implements the assignment operator for char*, but
>
> even if it does not, the constructor will be called and then assigned to the instance because the
>
> constructor accepts a char*.> >> Second is error-prone and should not be used!
>
>
>
> Agreed, it's very bad style.-N
-
On 20/02/2013 at 09:50, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Wrong, it's simply class-construction.
-NiklasNo. I'm not wrong.
When you create a class member variable. You do not then re-assign a new type specifier to it when you go to use it.@WickedP.
I've also found problems with getting zero returns. Even when doing top down sharing.
Apparently even top down class sharing in these plugins is not as simple as I thought.
I've figured out how to solve the zero return problem by making one class a friend of the other.
But so far I'm only getting the class member's initial constructor value.
If I change the value of the top class member. I don't get the new changed in the bottom class.
I need to work on it some more.@Remo:
Using the Alloc() method proved to be a dead end for me because it only returns BaseList2D elements. It does not inclue any of the custom class members in the class.
Using "friend class" seems to be the best method I've tried so far. The one that's produced the best results for me. But I'm still trying to flesh it all out and get updated values to work.-ScottA