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

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

        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 🙂

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

          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

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

            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!

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

              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

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

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

                Originally posted by xxxxxxxx

                Wrong, it's simply class-construction.
                -Niklas

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

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

                  On 20/02/2013 at 10:22, xxxxxxxx wrote:

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

                  _
                  _
                  Probably a misunderstanding. What I figured from your post, is that WP should use

                  > String myString;
                  >
                  > /* ... */
                  >
                  > myString = "Hello";

                  Instead of

                  > String myString;
                  >
                  > /* ... */
                  >
                  > myString = String("Hello");

                  .. because that would redeclare the variable. Is that what you said?

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

                    On 20/02/2013 at 11:38, xxxxxxxx wrote:

                    Yeah.
                    I noticed he seemed to be in the habit of re-declaring a class variable when he shouldn't be.

                    -ScottA

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

                      On 20/02/2013 at 12:15, xxxxxxxx wrote:

                      But

                      myString = String("Hello");

                      does not redeclare the variable. It creates a String object using the String constructor and assigns
                      it to the local variable myString. If it would redeclare the variable, this would print 5, but it prints 10:

                      >
                      > int main() {
                      > int a = 5;
                      > a = int(10);
                      >
                      > std::cout << a;
                      > }

                      http://codepad.org/G8RsKyhD

                      PS: More extended example: http://codepad.org/rGUgwY0j

                      -Niklas

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

                        On 20/02/2013 at 12:28, xxxxxxxx wrote:

                        Using the Alloc() method proved to be a dead end for me because it only returns BaseList2D elements.

                        You may need to make proper cast.

                          
                            
                            
                            // be sure to use a unique ID obtained from www.plugincafe.com
                            #define ID_LOOKATCAMERATAG	1001165
                            class LookAtCameraData : public TagData
                            {
                            	//...
                            public:
                            	String my_string;
                            };
                             
                            void Test()
                            {
                            	AutoFree<BaseTag> tag = BaseTag::Alloc(ID_LOOKATCAMERATAG);
                            	//or //BaseTag *tag = doc->GetActiveTag();
                            	if(tag){
                            		LookAtCameraData *data_ptr = static_cast<LookAtCameraData*>(tag->GetNodeData());
                            		GePrint(data_ptr->my_string);
                            	}
                            }
                            
                          
                        

                        > Apparently even top down class sharing in these plugins is not as simple as I thought.
                        Really do not udestand this problem.
                        It work in both directions.

                        Remo

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

                          On 20/02/2013 at 13:05, xxxxxxxx wrote:

                          ^I don't understand how creating a test() method that points back to the same plugin (the tag) it's residing in. Helps me to use that string class member within my GeDialog?

                          When I tried it. I tried to do this kind of thing from within the GeDialog. So that the dialog could use the tag's class members.
                          I tried to allocate a tag instance using the same code you're using. But I did it from inside of the GeDialog. Not from inside the Tag.
                          That might be why it didn't work. I'm really terrible at casting BTW.

                          Your example works for me if I use it inside my tag class.
                          But that leaves me wondering...OK...so now what?
                          How does doing this allow my GeDialog to see and use the tag's "my_string" class member's value?

                          -ScottA

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

                            On 20/02/2013 at 14:32, xxxxxxxx wrote:

                            You'll have to pass the tag pointer to the GeDialog either to store as a member variable or as just a function argument. As long as my_string is public.  If not, then you need to create an access method (like:

                            String LookAtCameraData::GetMyString()  
                            {  
                            return my_string;  
                            }
                            
                            // be sure to use a unique ID obtained from www.plugincafe.com  
                            #define ID_LOOKATCAMERATAG    1001165  
                            class LookAtCameraData : public TagData  
                            {  
                              //...  
                            public:  
                              String my_string;  
                            };  
                               
                              
                            void GeDialog::Test(BaseTag* tag)  
                            {  
                              if(tag)  
                              {  
                                  LookAtCameraData *data_ptr = static_cast<LookAtCameraData*>(tag->GetNodeData());  
                                  GePrint(data_ptr->my_string);  
                              }  
                            }  
                            
                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              On 20/02/2013 at 14:53, xxxxxxxx wrote:

                              Thanks Robert.
                              I just realized my silly mistake.
                              The Test() method Remo posted was never meant to be included inside of the tag's class structure.
                              It's meant to be posted after it. Below the Tag's registration code.

                              Example:

                              void Test();  //Forward declare the method so it can be used in the GeDialog class  
                                
                              class MyDialog : public GeDialog  
                              {  
                                public:  
                                
                                //Overrides  
                                    Bool CreateLayout();  
                                    Bool InitValues();  
                                    Bool Command(LONG id, const BaseContainer& data);  
                                    Bool CoreMessage(LONG id, const BaseContainer& data);  
                                
                              };  
                                
                              ...The rest of the dialog's stuff  
                              ////////////////////////////////////////////////////////////////  
                              ////////////////////////////////////////////////////////////////  
                                
                              class StorageTag : public TagData  
                              {  
                                public:  
                                    static NodeData* Alloc()  
                                {  
                                        return gNew StorageTag;  
                                    }  
                                
                                    String my_string;  
                                 
                                
                                //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);  
                              };  
                                
                              ...The rest of the Tag's stuff  
                                
                              ////////////////////////////////////////////////////////////////  
                              ///////////////////////////////////////////////////////////////  
                                
                              void Test()  
                              {  
                                AutoFree<BaseTag> tag = BaseTag::Alloc(TAG_PLUGIN_ID);   //or use: BaseTag *tag = doc->GetActiveTag();  
                                  
                                if(tag)  
                                {  
                                    StorageTag *data_ptr = static_cast<StorageTag*>(tag->GetNodeData());  
                                    GePrint(data_ptr->my_string);  
                                }  
                              }
                              

                              I knew I was missing something stupid. I just had to find it.!Embarrassed[URL-REMOVED]
                              I'll give this new method a try for a while and see if I run into any problems.

                              Thanks Remo.
                              -ScottA


                              [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 20/02/2013 at 20:28, xxxxxxxx wrote:

                                Other examples have already been given, but I'm going to post another to try and tie everything together, using complete examples. We begin with code that won't compile (note that in C++, structs are the same as classes, but with default public access, so they can be nice for making uncluttered examples), and show where, and why, it is failing:

                                  
                                struct A {   
                                int foo(B& b) {   // <- error: 'B' has not been declared   
                                    return b.i;   
                                }   
                                };   
                                struct B {   
                                int i;   
                                };   
                                int main() {   
                                A a = A();   
                                B b = B();   
                                return a.foo(b);   
                                }   
                                

                                Okay, the compiler says 'B' has not been declared, so let's fix this by forward declaring B before attempting to use it from within A:

                                  
                                struct B;           // <- forward declare B   
                                struct A {   
                                int foo(B& b) {   
                                    return b.i;     // <- error: invalid use of undefined type 'struct B'   
                                }   
                                };   
                                struct B {   
                                int i;   
                                };   
                                int main() {   
                                A a = A();   
                                B b = B();   
                                return a.foo(b);   
                                }   
                                

                                What did the forward declaration do? It got us one line further. But note the difference in the errors: the first complained about declaration, the second about use of undefined type 'B'. This shows that the compiler now knows of a label called 'B', thanks to our forward declaration, but it still has no idea what, or where B::i is. Just as we made the compiler aware of the existence of B with a declaration, we will solve this problem by turning our definition of A::foo(B&) into a declaration, and deferring its definition until after B has been fully defined:

                                  
                                struct B;           // <- forward declare B   
                                struct A {   
                                int foo(B& b);    // <- declare(only!) A::foo(B&)   
                                };   
                                struct B {   
                                int i;   
                                };   
                                int A::foo(B& b) { // <- define A::foo(B&)   
                                return b.i;       // <- ok: B is fully defined   
                                }   
                                int main() {   
                                A a = A();   
                                B b = B();   
                                return a.foo(b); // <- ok: A & B are fully defined   
                                }   
                                

                                Now we're golden. Something to note is that there is no special place (e.g. the very bottom of the file) that we have to do the definition -- the sole requirement is that any code it uses already be defined. In fact, what we have done here, in a single code region, is exactly the same as what we'd have done had we separated the code into h and cpp files. One reason (of many) for separating into h and cpp is that it helps us to remember to avoid mixing declarations and definitions. Just remember that if you #include a header, this is done by the preprocessor, and is equivalent to copy/pasting the entire contents of the header, verbatim, at the #include point.

                                A good mental check, if you run into a compilation issue, is to put yourself in the place of the compiler. Look at the usage, and ask yourself: would you need to read the rest of the code before you could identify a particular construct? Take the second example above; erase all code below the error, and look at the statement return b.i; You'll find yourself in agreement with the compiler, that there is not yet enough information to do the job.

                                To finish up this part of the example, though we already know, logically, since A is able to use B, that it follows A and B are able to use each other, for the sake of completeness, let's just prove it:

                                  
                                struct B;           // <- forward declare B   
                                struct A {   
                                int i;   
                                int foo(B& b);    // <- declare A::foo(B&)   
                                };   
                                struct B {   
                                int i;   
                                int bar(A& a);    // <- declare B::bar(A&)   
                                };   
                                int A::foo(B& b) { // <- define A::foo(B&)   
                                return b.i;       // <- ok: B is fully defined   
                                }   
                                int B::bar(A& a) { // <- define B::bar(A&)   
                                return a.i;       // <- ok: A is fully defined   
                                }   
                                int main() {   
                                A a   = A();   
                                B b   = B();   
                                int i = a.foo(b); // <- ok: A & B are fully defined   
                                int j = b.bar(a); // <- ok: A & B are fully defined   
                                return 0;   
                                }   
                                

                                Now, with this out of the way, some further comments regarding the prior mention of difficulties with "top-down sharing." As we have seen above, it is entirely possible to do this, provided we allow the compiler to understand the code we are using, at the point we use it. There is, however, one thing we will find quite impossible: to include an instance of B as a data member of A. Why? Witness the objects of infinite static size:

                                  
                                struct A {   
                                B b;              // <- error: field 'b' has incomplete type   
                                };   
                                struct B {   
                                A a;   
                                };   
                                int main() {   
                                A a;   
                                a.b.a.b.a.b.a.b.a.b.a.b.a.b.a.b.a.b.a.b.....   
                                return 0;   
                                }   
                                

                                This, could you compile it, would be equivalent to recursively including an instance of A as a data member of itself -- it just happens here indirectly, through the inclusion of an instance of B. Imagine though, that we were dealing not with two tiny classes, and rather with a large and complicated object model. How long would it be before you inadvertently tried to do exactly this? By the time you realized it, much design work might already have been done, and you could be looking at a costly re-design.

                                By definition, the C++ compilation rules prevent this from being possible. In languages with more flexible compilation rules though, C# for example, if you define a struct which includes an instance of itself, the compiler must explicitly check for, and catch this; you will receive an error stating "Struct member 'foo' of type 'Foo' causes a cycle in the struct layout."

                                It is, of course, perfectly fine to go the other way round and include an instance of A in B, because by that time we do that, A has been fully defined, and there is no longer any possibility of generating a recursive definition. So the final piece to the puzzle is: what if we really do want A and B to contain instances of each other, or even of themselves? It must be done using pointers:

                                  
                                struct B;   
                                struct A {   
                                B *b;   
                                A *foo();   
                                };   
                                struct B {   
                                A *a;   
                                B *bar();   
                                };   
                                A *A::foo() {   
                                return b->a;   
                                }   
                                B *B::bar() {   
                                return a->b;   
                                }   
                                int main() {   
                                A a = A();   
                                B b = B();   
                                a.b = &b;   
                                b.a = &a;   
                                A *pA = a.foo();   
                                B *pB = b.bar();   
                                return pA - b.a + pB - a.b;   
                                }   
                                

                                Note that it is still necessary for classes to be fully defined before they are actually used. The primary function of the C++ compiler is to read your code and generate the blueprints for turning it into memory layouts at runtime; to do that, it needs to figure out how large they are, and at what relative memory offsets their data and methods are located. It follows, then, that in order to generate the layout for an object, any object used inside that object must already have been fully defined, and so on.

                                Hopefully this is helpful in furthering your understanding of C++, and in dispelling any notions you may have that it could somehow work differently in Cinema plugins than it does elsewhere -- because it doesn't.

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

                                  On 22/02/2013 at 03:26, xxxxxxxx wrote:

                                  Thanks JDHill,
                                   
                                  that provides some sense and order. I seem to have managed to get the function in the following class to receive and print the string value now. However there's still one small issue I can't seem to resolve. I can't attach the functions new string value to a local string. Example below of what I'm referring too (my apologies for any syntax errors etc, it's just for demo, hope you see what I mean!) :
                                   
                                  This works fine:

                                  class MyClass2;
                                  class MyClass1
                                  {
                                  MyClass2 *MC2;
                                  public:
                                    MyFunction();
                                  };
                                   
                                  class MyClass2
                                  {
                                  MyClass1 *MC1;
                                  String LocalString;  // local string variable - not used in this example
                                  public:
                                      Class2MyFunction(String PassingString)
                                      {
                                          return PassingString;
                                      }
                                  };
                                   
                                  MyClass1::MyFunction()
                                  {
                                      String pass = "Blah";
                                      MC2.Class2MyFunction(pass);
                                      return TRUE;
                                  }
                                  

                                  This one however, crashes cinema (the difference is in trying to declare the local string in MyClass2's function) :

                                  class MyClass2;
                                  class MyClass1
                                  {
                                      MyClass2 *MC2;
                                  public:
                                      MyFunction();
                                  };
                                  class MyClass2
                                  {
                                  String LocalString; // local string variable
                                  MyClass1 *MC1;
                                  public:
                                      Class2MyFunction(String& PassingString)
                                      {
                                          LocalString = PassingString;  // crashes..
                                          return PassingString;
                                      }
                                  };
                                  MyClass1::MyFunction()
                                  {
                                  String pass = "Blah";
                                  MC2.Class2MyFunction(pass);
                                  return TRUE;
                                  }
                                  

                                  What's the trick I'm missing here?
                                   
                                  WP.

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

                                    On 22/02/2013 at 07:44, xxxxxxxx wrote:

                                    First of all, by standard, you should pass by const reference when you do not change the reference (goes back to C++ standard saying "non-const references cannot bind to temporary objects"...it's always good advice anyway!). Then you should not assign the string but initialise it directly in the constructor initialisation list like:

                                    Class2MyFunction(const String& PassingString) : LocalString(PassingString) {}
                                    

                                    There is also no return value for the constructor.

                                    But I just see (silly me) that this is not your constructor so it should just be constant (and of course it lacks a return value definition in front of the function). But I leave the above text for completeness 🙂

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

                                      On 22/02/2013 at 22:57, xxxxxxxx wrote:

                                      WickedP, your second example should not compile (I didn't check the first), so I'm not sure how you know that it crashes. Please take a look at the following and see if it helps. It is just two tiny classes, Data and Proxy, where Data has a String, and Proxy has a Data*. So if you create a Data, and a Proxy that uses it, the GetString/SetString methods of either will get/set the Data's string.

                                        
                                      ////////////////////////////////////////////////////////   
                                      // We don't really need to forward Proxy, but it can't   
                                      // hurt. If we put this in another file, declaring   
                                      // everything here would give us a nice overview.   
                                        
                                      class Proxy;   
                                      class Data;   
                                        
                                      ////////////////////////////////////////////////////////   
                                      // The Proxy class represents an object which doesn't   
                                      // have any real data of its own. Instead, it must ask   
                                      // its private Data pointer to get and set data for it.   
                                        
                                      class Proxy {   
                                          Data *data;   
                                      public:   
                                          Proxy(Data *d);   
                                          String GetString() const;   
                                          void SetString(const String &s;);   
                                      };   
                                        
                                      ////////////////////////////////////////////////////////   
                                      // The Data class represents an object which contains   
                                      // data, but which has no knowledge of other classes.   
                                        
                                      class Data {   
                                          String string;   
                                      public:   
                                          Data(String s);   
                                          String GetString() const;   
                                          void SetString(const String &s;);   
                                      };   
                                        
                                      ////////////////////////////////////////////////////////   
                                      // Definition of Proxy methods:   
                                        
                                      Proxy::Proxy(Data *d) : data(d) {   
                                      }   
                                      String Proxy::GetString() const {   
                                          return data->GetString();   
                                      }   
                                      void Proxy::SetString(const String &s;) {   
                                          data->SetString(s);   
                                      }   
                                        
                                      ////////////////////////////////////////////////////////   
                                      // Definition of Data methods:   
                                        
                                      Data::Data(String s) : string(s) {   
                                      }   
                                      String Data::GetString() const {   
                                          return string;   
                                      }   
                                      void Data::SetString(const String &s;) {   
                                          string = s;   
                                      }   
                                        
                                      ////////////////////////////////////////////////////////   
                                        
                                      int main() {   
                                          // Create a Data and a Proxy:   
                                          Data data("data");   
                                          Proxy proxy(&data;);   
                                        
                                          // Check that they both print "data"   
                                        
                                          GePrint("data: " + data.GetString());   
                                          GePrint("proxy: " + proxy.GetString());   
                                        
                                          // Set the string through Data and check:   
                                        
                                          data.SetString("Data::SetString");   
                                          GePrint("data: " + data.GetString());   
                                          GePrint("proxy: " + proxy.GetString());   
                                        
                                          // Set the string through Proxy and check:   
                                        
                                          proxy.SetString("Proxy::SetString");   
                                          GePrint("data: " + data.GetString());   
                                          GePrint("proxy: " + proxy.GetString());   
                                      }   
                                      

                                      (and by the way, an OT question for anyone reading this: whenever I post on this forum, the code tags always use a double line height for my code -- how are you guys avoiding that? I've tried using firefox, chrome, and IE, and also win/unix/mac line-endings, so far with no luck.)

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

                                        On 23/02/2013 at 08:19, xxxxxxxx wrote:

                                        ^In my experience. This forum can't handle any tabs in your code.
                                        If you want the code to be nice and tight. You'll have to remove any tabs from it and only use spaces.

                                        -ScottA

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

                                          On 23/02/2013 at 09:33, xxxxxxxx wrote:

                                          Thanks, but I don't ever use tabs, it's something else. Looking at the html, there actually appear to be three different ways it is generated for different poster's code tags, but as this is OT, I'm going to make a different thread for it.

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

                                            On 23/02/2013 at 11:42, xxxxxxxx wrote:

                                            All people that post from mac have this problem.

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