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

2019-01-22 02:16发布

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();

Then, in my code, I would call it like this:

    Object myObject = return_Object();

I have written code like this and it compiles. However, when I run the code, I consistently get a seg fault. What is the proper way to return a class object by reference?

5条回答
Anthone
2楼-- · 2019-01-22 02: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;
         }
   };
查看更多
做自己的国王
3楼-- · 2019-01-22 02:49

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;
}
查看更多
够拽才男人
4楼-- · 2019-01-22 02:52

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!

查看更多
SAY GOODBYE
5楼-- · 2019-01-22 02:57

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.

查看更多
甜甜的少女心
6楼-- · 2019-01-22 03:05

I will show you some examples:

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

const string &mainip(const string &s)
{
    string ret=s;

    //  operator ret

    return ret;
}

you can't return ret by reference, because ret is destructed at the end.

Second example, you can return by reference:

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

you can return by reference for both s1 and s2 is still existing.

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

because after return by reference the object is still exists;

Fourth example

class Student{
    public:
        string m_name;
        int age;    

        string& getName();
};

string& Student::getName(){  // you can return by reference
    return m_name;
}

// you can return by reference, after this function stu object is still exists
string& Test(Student &stu)
{
    return stu.m_name;
}

usage example:

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

Fifth example:

class String{
    private:
        char* str_;

    public:
        String& operator=(const String& str);
};

// for example a=b=c usage
String& String::operator =(const String &str)   
{
    if (this == &str)
    {
        return *this;
    }
    delete [] str_;
    int len = strlen(str.str_);
    str_ = new char[len+1];
    strcpy(str_,str.str_);
    return *this;
}
查看更多
登录 后发表回答