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 17/02/2013 at 13:48, xxxxxxxx wrote:

      What do you mean with 'not working'? Declaring, implementing, overriding, calling, referencing, .. ?

      Edit: Just seen your edit, wait a moment pls.

      --------

      Were do you define the class then? Could you please show me the
      (complete) headers and the implementation files? It is very important
      where you do the forward-declaration, the definition, the implemenation
      and the usage.

      The Cinema API is using many forward-declarations btw.

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

        On 17/02/2013 at 14:00, xxxxxxxx wrote:

        Sorry but this example makes no sense to me.

        What exactly do you want to do?

        > You can definitely use a forward class definition this way to share class members between classes.
        Share class members, may be you should take a look at std::shared_ptr or boost equivalent of it.

        This would make sense.
        Of course you need to make sure that the pointer are always valid, because C4D (user) may delete you Tag any time and the point will be invalid.
        NodeData[URL-REMOVED]* GetNodeData(LONG index = 0) can be used to get it.
        Look at  hair_render.cpp  example for this.

          
            
            
            class MyTag;     
             
            class MyDialog : public GeDialog
            {
            public:
            	MyTag   *tag;  //Actually this is really dangerous and should not be made !!!  
                
            	//GeDialog Overrides
            	//Blah, blah, etc..
            
            };
            
            class MyTag : public TagData
            {
            public:
             
            	MyDialog  *dlg; //Actually this is really dangerous and should not be made !!!    
             
            	//TagData Overrides
            	//Blah, blah, etc..
             
            };
          
        

        Actually this is really dangerous and should not be made !!!


        [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 17/02/2013 at 14:05, xxxxxxxx wrote:

          And btw: Using cyclic non-pointers would lead to infinite memory consumption.

          class B;
            
          class A {
              B b;
          };
            
          class B {
              A a;
          };
          

          This would be technically impossible.

          Remo: Would you mind to elobarate more on why it is dangerous, what
          you have mentioned?

          Edit: ah I see. Dangerous because the pointer could be invalid, not
          because of security reasons. 🙂

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

            On 17/02/2013 at 14:46, xxxxxxxx wrote:

            If I use a pointer like in Remo's example. The minute I try to use that pointer in my plugin code. I get an undefined class error.

            Sharing the top class's members with the bottom class is a no brainer. It's like pouring water down a drain. It's simple and easy.
            But sharing a bottom class's members with the the previous class (top class) is something I've only been able to do in raw C++. And not at all in C4D plugins.
            The friend class is a completely separate approach I was trying out.
            I was looking for a way to share the members of two different classes without using a third shared class or struct. And on the internet there's lots of examples of using a friend class to do this sharing in both directions.
            But in C4D plugins none of this stuff is working for me like it does in raw C++.

            The main differences I'm seeing between working in Raw C++ vs C4D plugins:
            Raw: In raw C++ I spend lots of time inside the main() function.
            C4D: In C4D plugins I spend almost no time at all in the main function (main.cpp).
            Raw: In raw C++. I almost never inherit from another class. It's not something I need to do very often.
            C4D: In C4D plugins. Almost everything is inherited from another class.

            Sharing a class's members with a lower class                --> simple in Raw C++ and C4D
            Sharing a class's members upwards to a previous class -->simple in Raw C++...But cannot do it in C4D plugins

            -ScottA

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

              On 17/02/2013 at 15:09, xxxxxxxx wrote:

              My be you want to do something like this:
              This is based on triangulate.cpp and menutest.cpp from c4d_sdk

                
                  
                  
                  ///menutest.cpp
                  
                
                  
                  
                  #include "c4d.h"
                  #include "c4d_symbols.h"
                   
                  #include "../object/triangulate.h"
                  
                  
                  class MenuTest : public CommandData
                  {
                  	public:
                  		virtual Bool Execute(BaseDocument *doc);
                  };
                   
                  Bool MenuTest::Execute(BaseDocument *doc)
                  {
                  	if(!doc){ GePrint("!doc");  return false; }
                  	BaseObject *obj = doc->GetActiveObject();  
                  	if(!obj){ GePrint("No Object Selected!");  return false; }
                   
                  	TriangulateData *tri_data = static_cast<TriangulateData*>( obj->GetNodeData() );
                   
                  	GePrint("String from Object:  <" + tri_data->GetMyString() + ">");
                   
                  	tri_data->mdata_ref = std::make_shared<MyData>(" MyData Name ");
                   
                   
                  	return true;
                  }
                   
                  Bool RegisterMenuTest(void)
                  {
                  	// be sure to use a unique ID obtained from www.plugincafe.com
                  	return RegisterCommandPlugin(1000956,GeLoadString(IDS_MENUTEST),0,AutoBitmap("icon.tif"),String("C++ SDK Menu Test Plugin"),gNew MenuTest);
                  }
                
              
                
                  
                  
                  ///triangulate.h
                  #include "c4d.h"
                   
                  #include <memory> //shared_ptr and more
                   
                  class MyData;
                  class MenuTest;
                   
                  //=====================================================================================================================
                  class TriangulateData : public ObjectData
                  {
                  	friend MenuTest;
                  private:
                  	TriangulateData() : m_object_string("TriangulateData") {    }
                   
                  	LineObject *PrepareSingleSpline(BaseObject *generator, BaseObject *op, Matrix *ml, HierarchyHelp *hh, Bool *dirty);
                  	void Transform(PointObject *op, const Matrix &m);
                   
                  public:
                  	virtual BaseObject* GetVirtualObjects(BaseObject *op, HierarchyHelp *hh);
                   
                  	const String& GetMyString() const { return m_object_string; }
                   
                  	static NodeData *Alloc(void) { return gNew TriangulateData; }
                  private:
                  	std::shared_ptr<MyData> mdata_ref;
                   
                  	String	m_object_string;
                  };
                  //=====================================================================================================================
                  class MyData
                  {
                  public:
                  	MyData() {}
                  	MyData(const String& str) :  m_str(str) {}
                   
                  	~MyData() { GePrint(" MyData destructor "); }
                   
                  	String m_str;
                  };
                
              
              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 17/02/2013 at 15:55, xxxxxxxx wrote:

                Interesting. There's a little bit of everything going on in that example.

                I just want to share a class's members upwards to the previous class.
                But this thing is also using friend, and shared pointers. And I'm not sure how much part those things are playing in that end goal.
                I'll have to study this thing for a while and try to see if I can simplify it with some more simplistic LONG type class member variables and see if I can get the MyData class to share upwards to the previous class.

                Thanks,
                -ScottA

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

                  On 17/02/2013 at 21:05, xxxxxxxx wrote:

                  Thanks for the conversation folks.
                  Over at my end however, it's still not recieving the right String value. Whenever I copy another string over to the functions string, it returns an empty value. See below for what I'm trying to do.
                  This one works:

                    
                  class MyClass1  
                  {  
                  public:  
                   String MyString(String temp)  
                    {  
                        temp = String("Print successful!");  
                        return temp;  
                    }  
                  };  
                  

                  But this one doesn't:

                    
                  class MyClass1  
                  {  
                  String AnotherString;    // class level String variable.  
                  public:  
                  Init(void)  
                    {  
                        AnotherString = String("This way won't work.");  
                    }  
                   String MyString(String temp)  
                    {  
                        // AnotherString (and 'temp') always returns empty when done this way  
                        // AnotherString = String("Doesn't work either.");    // uncommenting this line doesn't work either.  
                        temp = AnotherString;  
                        return temp;  
                    }  
                  };  
                  

                  What's the differene here? Why won't the second way work?
                  WP.

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

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

                    Hi WickedP,

                    what's the sense of passing a string that is not used at all? Are you calling Init() before MyString() ?
                    You're also missing the return-type for the Init() method. Also note that a void parameter is
                    deprecated for C++ and is used in C only.

                    http://ideone.com/GZeyoY

                    #include <string>
                    #include <iostream>
                     
                    class MyClass {
                        
                        std::string my_string;
                        
                    public:
                     
                        void Init() {
                            my_string = "Hello!";
                        }
                        
                        std::string GetMyString() {
                            return my_string;
                        }
                        
                    };
                     
                    int main() {
                        MyClass obj;
                        obj.Init();
                        std::cout << obj.GetMyString();
                    }
                    

                    ScottA :

                    The following does not work: http://ideone.com/ASo7LI
                    The function MyFoo::DoStuff() is not declared since MyFoo is an incomplete type at the point
                    MyFoo::DoStuff() is used.

                    #include <string>
                    #include <iostream>
                     
                    #define PFUNC() do { std::cout << \__FUNCTION\_\_ << "\n"; } while (0)
                     
                    class MyFoo;
                     
                    class MyBar {
                        
                        MyFoo\* foo;
                     
                    public:
                     
                        MyBar(MyFoo\* foo) : foo(foo) {
                        }
                     
                        void DoStuff() {
                            PFUNC();
                    **         foo->DoStuff(); // MyFoo is still an incomplete type!**
                        }
                    };
                     
                    class MyFoo {
                        
                    public:
                     
                        void DoStuff() {
                            PFUNC();
                        }
                    };
                     
                    int main() {
                        MyFoo foo;
                        MyBar bar(&foo);
                        
                        bar.DoStuff();
                    }  
                    

                    Implementing MyBar::DoStuff() after MyFoo became a complete type, it
                    works: http://ideone.com/3G2Xub

                    #include <string>
                    #include <iostream>
                     
                    #define PFUNC() do { std::cout << \__FUNCTION\_\_ << "\n"; } while (0)
                     
                    class MyFoo;
                     
                    class MyBar {
                        
                        MyFoo\* foo;
                     
                    public:
                     
                        MyBar(MyFoo\* foo) : foo(foo) {
                        }
                     
                        ** void DoStuff();**
                    };
                     
                    class MyFoo {
                        
                    public:
                     
                        void DoStuff() {
                            PFUNC();
                        }
                    };
                     
                    **void MyBar ::DoStuff() {
                        PFUNC();
                        foo->DoStuff(); // MyFoo is now a complete type!
                    }**
                     
                    int main() {
                        MyFoo foo;
                        MyBar bar(&foo);
                        
                        bar.DoStuff();
                    }
                    

                    If that's not what you mean, and does not solve the problem, could you please post a full
                    example that you think should compile but doesn't because of the undefined class error?

                    -Niklas

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

                      On 18/02/2013 at 01:56, xxxxxxxx wrote:

                      Hi Nik,
                      just to clarify a few points for you:

                      Originally posted by xxxxxxxx

                      what's the sense of passing a string that is not used at all?

                      the string is used in MyClass1 (which is actually a GeUserArea) but the userarea code is hundreds of lines long so I was a bit reluctant to paste all of that. The example I've been providing above is just a basic translated version of what I have.

                      Originally posted by xxxxxxxx

                      Are you calling Init() before MyString() ?

                      As it's a user area, Init is called first. However the string is being updated/defined in a few other functions so it is in use elsewhere, and is for other purposes.

                      Originally posted by xxxxxxxx

                      You're also missing the return-type for the Init() method. Also note that a void parameter is
                      deprecated for C++ and is used in C only.

                      My mistake in translating things over. Needless to say the string (and the GeUserArea) all runs as expected, and the string variable is filled well before any call to the "MyString()" function is run. The issue seems to be if you get the function's string value from another variable - the string value (both the function's and the class level variable) are when passed to another class.
                       
                      Cheers,
                       
                      WP.

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

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

                        Originally posted by xxxxxxxx

                        Sure.Here's a small example:

                        class MyTag;                <-- In raw C++ this is how you tell the compiler to go get the MyTag class   
                                                        Problem: This works fine in raw C++. But not when doing it inside of a C4D plugin.   
                         
                        class MyDialog : public GeDialog{   
                            public:        MyTag tag;           <--- Complier error: Undefined class!!?   
                                GeDialog Overrides   
                                Blah, blah, etc..   
                          };   
                         
                        class MyTag : public TagData{   
                            public:        MyDialog dlg;         <--- MyDialog has been seen by the compiler and works fine   
                                                           Note: This works fine in both raw C++ and in C4D plugins   
                                TagData Overrides   
                                Blah, blah, etc..   
                         };   
                        

                        Originally posted by xxxxxxxx

                        this shouldn't work in a "raw C++" environment, either.

                        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.

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

                          On 18/02/2013 at 03:31, xxxxxxxx wrote:

                          Hi Jack,
                           
                          the behaviour with the forward declaring seems to be different, as I get the same compiler error as Scott when forward declaring like that in a C4D plugin.
                           
                          WP.

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

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

                            Originally posted by xxxxxxxx

                            Hi Jack,
                             
                            the behaviour with the forward declaring seems to be different, as I get the same compiler error as Scott when forward declaring like that in a C4D plugin.
                             
                            WP.

                            "In C++, classes can be forward-declared if you only need to use the pointer-to-that-class type (since all object pointers are the same size, and this is what the compiler cares about)."

                            Can't use forwards declation with

                            MyTag tag;
                            

                            It's just C++, guys. Nothing funny going on here at all.

                            1 Reply Last reply Reply Quote 0
                            • 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
                                            • First post
                                              Last post