Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Returning another class' function value

    SDK Help
    0
    61
    54.6k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 18/02/2013 at 04:29, xxxxxxxx wrote:

      Yes, that's right. The problem you get is usually because the compiler did not parse the classes definition
      at the point you want to access a member in the current translation unit. When you forward-declare a class
      from a header that does not define the class, you must at least include the header defining the class in the
      implementation file so the compiler knows about its definition when the class is used.

      -N

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 18/02/2013 at 07:50, xxxxxxxx wrote:

        Originally posted by xxxxxxxx

        That's a normal forward declaration, and it works. I use it all the time.
        To clarify, there is nothing like "CINEMA 4D C++". It's all the same. Standard compiler, standard language, just some custom classes and structs.
        No difference in language behavior whatsoever.

        Can you post a working example of bottom up class sharing then?
        Fused is correct about the pointer. I posted my example from memory. And I forgot to use a pointer to the bottom class's prototype in my example. It's been a while since I tried doing this and forgot about the pointer.
        But even if I do use a pointer to the bottom class's prototype. I still get an undefined class error when I try to actually use that pointer in my code.

        Again.
        In Raw C++ it's very common to do a bottom up type of sharing of a class to it's previous class.
        But in C4D plugins it's not something I can do at all. And apparently other people are having the same problem.
        We need to see a working example of bottom up class sharing.

        -ScottA

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 18/02/2013 at 08:13, xxxxxxxx wrote:

          Like this one ?

            
              
              
              class SecondOne;
               
              //=====================================================================================================================
              class FirstOne
              {
              	friend SecondOne;
              public:
              	FirstOne(SecondOne &ref) 
              		: m_first_string("first_string")
              		, m_ref_to_second(ref)
              	{}
               
              	void Print();
              	void PrintSecond(SecondOne &ref);
              private:
              	String m_first_string;
               
              	SecondOne	&m_ref_to_second;
              };
               
              //=====================================================================================================================
              class SecondOne
              {
              	friend FirstOne;
              public:
              	SecondOne() 
              		: m_second_string("second_string")
              		, m_first(*this) 
              	{}
               
              	void Print() { GePrint(m_first.m_first_string); }
              	void PrintFirst(FirstOne &ref);
               
              private:
              	String m_second_string;
               
              	FirstOne	m_first;
              };
               
              // ----------------------------------------------------------------------------------------------------
              void SecondOne::PrintFirst( FirstOne &ref )
              {
              	GePrint(ref.m_first_string);
              }
              // ----------------------------------------------------------------------------------------------------
              void FirstOne::PrintSecond(SecondOne &ref)
              {
              	GePrint(ref.m_second_string);
              }
              // ----------------------------------------------------------------------------------------------------
              void FirstOne::Print()
              {
              	GePrint(m_ref_to_second.m_second_string);
              }
            
            
          
          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 18/02/2013 at 08:27, xxxxxxxx wrote:

            Doh!
            I was going to edit my post to say that we need to see a working example of the bottom up class sharing. Using the existing SDK classes (tag, GeDialog, object, etc..). Not custom hand made classes.
            But you were too quick Remo.🙂

            I was wondering if maybe using generic custom classes to test this on isn't a good way to test this. Because custom classes don't have header files or inheritance in them the same as the built-in SDK classes.
            So I'm wondering if the reason I'm getting undefined class errors is because of the way the built-in SDK classes are set up with their .h files and inheritance structures.

            Do you happen to know if that code will also work for the built-in SDK classes Remo?
            Have you tried this using two of the existing SDK classes?

            -ScottA

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 18/02/2013 at 08:55, xxxxxxxx wrote:

              Hm, do you mean ObjectData, TagData ?
              The short answer is it is not allowed and make no sense.

              C4D own all this stuff.
              Of course you can still use pointers to it.
              BaseObject [URL-REMOVED]*obj= BaseObject[URL-REMOVED]::Alloc(MY_PLUGIN_ID);

              An the ObjectData is then inside of BaseObject.[URL-REMOVED]
              This can be acceded using GetNodeData().


              [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 18/02/2013 at 09:50, xxxxxxxx wrote:

                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.
                -ScottA

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  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.-ScottA

                  You 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

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    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.   
                        }   
                    };   
                      
                    
                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      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

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        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());   
                            }
                        
                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          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

                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            On 18/02/2013 at 13:42, xxxxxxxx wrote:

                            You've missed the forward-declaration, then.

                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              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).

                              1 Reply Last reply Reply Quote 0
                              • H
                                Helper
                                last edited by

                                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).

                                1 Reply Last reply Reply Quote 0
                                • H
                                  Helper
                                  last edited by

                                  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

                                  1 Reply Last reply Reply Quote 0
                                  • H
                                    Helper
                                    last edited by

                                    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.   
                                      
                                    
                                    1 Reply Last reply Reply Quote 0
                                    • H
                                      Helper
                                      last edited by

                                      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

                                      1 Reply Last reply Reply Quote 0
                                      • H
                                        Helper
                                        last edited by

                                        On 18/02/2013 at 15:24, xxxxxxxx wrote:

                                        lol

                                        1 Reply Last reply Reply Quote 0
                                        • H
                                          Helper
                                          last edited by

                                          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.

                                          1 Reply Last reply Reply Quote 0
                                          • H
                                            Helper
                                            last edited by

                                            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

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post