How to return a class object by reference in C++?

后端 未结 5 1458
北恋
北恋 2020-12-07 20:53

I have a class called Object which stores some data.

I would like to return it by reference using a function like this:

    Object& return_Object         


        
相关标签:
5条回答
  • 2020-12-07 21:33

    Well, it is maybe not a really beautiful solution in the code, but it is really beautiful in the interface of your function. And it is also very efficient. It is ideal if the second is more important for you (for example, you are developing a library).

    The trick is this:

    1. A line A a = b.make(); is internally converted to a constructor of A, i.e. as if you had written A a(b.make());.
    2. Now b.make() should result a new class, with a callback function.
    3. This whole thing can be fine handled only by classes, without any template.

    Here is my minimal example. Check only the main(), as you can see it is simple. The internals aren't.

    From the viewpoint of the speed: the size of a Factory::Mediator class is only 2 pointers, which is more that 1 but not more. And this is the only object in the whole thing which is transferred by value.

    #include <stdio.h>
    
    class Factory {
      public:
        class Mediator;
    
        class Result {
          public:
            Result() {
              printf ("Factory::Result::Result()\n");
            };
    
            Result(Mediator fm) {
              printf ("Factory::Result::Result(Mediator)\n");
              fm.call(this);
            };
        };
    
        typedef void (*MakeMethod)(Factory* factory, Result* result);
    
        class Mediator {
          private:
            Factory* factory;
            MakeMethod makeMethod;
    
          public:
            Mediator(Factory* factory, MakeMethod makeMethod) {
              printf ("Factory::Mediator::Mediator(Factory*, MakeMethod)\n");
              this->factory = factory;
              this->makeMethod = makeMethod;
            };
    
            void call(Result* result) {
              printf ("Factory::Mediator::call(Result*)\n");
              (*makeMethod)(factory, result);
            };
        };
    };
    
    class A;
    
    class B : private Factory {
      private:
        int v;
    
      public:
        B(int v) {
          printf ("B::B()\n");
          this->v = v;
        };
    
        int getV() const {
          printf ("B::getV()\n");
          return v;
        };
    
        static void makeCb(Factory* f, Factory::Result* a);
    
        Factory::Mediator make() {
          printf ("Factory::Mediator B::make()\n");
          return Factory::Mediator(static_cast<Factory*>(this), &B::makeCb);
        };
    };
    
    class A : private Factory::Result {
      friend class B;
    
      private:
        int v;
    
      public:
        A() {
          printf ("A::A()\n");
          v = 0;
        };
    
        A(Factory::Mediator fm) : Factory::Result(fm) {
          printf ("A::A(Factory::Mediator)\n");
        };
    
        int getV() const {
          printf ("A::getV()\n");
          return v;
        };
    
        void setV(int v) {
          printf ("A::setV(%i)\n", v);
          this->v = v;
        };
    };
    
    void B::makeCb(Factory* f, Factory::Result* r) {
          printf ("B::makeCb(Factory*, Factory::Result*)\n");
          B* b = static_cast<B*>(f);
          A* a = static_cast<A*>(r);
          a->setV(b->getV()+1);
        };
    
    int main(int argc, char **argv) {
      B b(42);
      A a = b.make();
      printf ("a.v = %i\n", a.getV());
      return 0;
    }
    
    0 讨论(0)
  • 2020-12-07 21:41

    I will show you some examples:

    First example, do not return local scope object, for example:

    const string &dontDoThis(const string &s)
    {
        string local = s;
        return local;
    }
    

    You can't return local by reference, because local is destroyed at the end of the body of dontDoThis.

    Second example, you can return by reference:

    const string &shorterString(const string &s1, const string &s2)
    {
        return (s1.size() < s2.size()) ? s1 : s2;
    }
    

    Here, you can return by reference both s1 and s2 because they were defined before shorterString was called.

    Third example:

    char &get_val(string &str, string::size_type ix)
    {
        return str[ix];
    }
    

    usage code as below:

    string s("123456");
    cout << s << endl;
    char &ch = get_val(s, 0); 
    ch = 'A';
    cout << s << endl; // A23456
    

    get_val can return elements of s by reference because s still exists after the call.

    Fourth example

    class Student
    {
    public:
        string m_name;
        int age;    
    
        string &getName();
    };
    
    string &Student::getName()
    {
        // you can return by reference
        return m_name;
    }
    
    string& Test(Student &student)
    {
        // we can return `m_name` by reference here because `student` still exists after the call
        return stu.m_name;
    }
    

    usage example:

    Student student;
    student.m_name = 'jack';
    string name = student.getName();
    // or
    string name2 = Test(student);
    

    Fifth example:

    class String
    {
    private:
        char *str_;
    
    public:
        String &operator=(const String &str);
    };
    
    String &String::operator=(const String &str)
    {
        if (this == &str)
        {
            return *this;
        }
        delete [] str_;
        int length = strlen(str.str_);
        str_ = new char[length + 1];
        strcpy(str_, str.str_);
        return *this;
    }
    

    You could then use the operator= above like this:

    String a;
    String b;
    String c = b = a;
    
    0 讨论(0)
  • 2020-12-07 21:44

    You can only return non-local objects by reference. The destructor may have invalidated some internal pointer, or whatever.

    Don't be afraid of returning values -- it's fast!

    0 讨论(0)
  • 2020-12-07 21:49

    You can only use

         Object& return_Object();
    

    if the object returned has a greater scope than the function. For example, you can use it if you have a class where it is encapsulated. If you create an object in your function, use pointers. If you want to modify an existing object, pass it as an argument.

      class  MyClass{
          private:
            Object myObj;
    
          public:
             Object& return_Object() {
                return myObj;
             }
    
             Object* return_created_Object() {
                return new Object();
             }
    
             bool modify_Object( Object& obj) {
                //  obj = myObj; return true; both possible
                return obj.modifySomething() == true;
             }
       };
    
    0 讨论(0)
  • 2020-12-07 21:54

    You're probably returning an object that's on the stack. That is, return_Object() probably looks like this:

    Object& return_Object()
    {
        Object object_to_return;
        // ... do stuff ...
    
        return object_to_return;
    }
    

    If this is what you're doing, you're out of luck - object_to_return has gone out of scope and been destructed at the end of return_Object, so myObject refers to a non-existent object. You either need to return by value, or return an Object declared in a wider scope or newed onto the heap.

    0 讨论(0)
提交回复
热议问题