如何在C++中通过引用返回类对象

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

本文关键字:引用 返回 对象 C++      更新时间:2023-10-16

我有一个名为Object的类,它存储一些数据。

我想通过引用返回它,使用这样的函数:

    Object& return_Object();

然后,在我的代码中,我会这样称呼它:

    Object myObject = return_Object();

我写过这样的代码,它可以编译。然而,当我运行代码时,我总是会遇到seg错误。通过引用返回类对象的正确方法是什么?

您可能正在返回堆栈上的对象。也就是说,return_Object()可能看起来像这样:

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

如果你就是这么做的,那你就倒霉了——object_to_return已经超出了范围,在return_Object结束时被破坏了,所以myObject指的是一个不存在的对象。您需要按值返回,或者将在更大范围内声明的Objectnew返回到堆中。

您只能使用

     Object& return_Object();

如果返回的对象的作用域大于函数的作用域。例如,如果您有一个封装它的类,则可以使用它。如果在函数中创建对象,请使用指针。如果要修改现有对象,请将其作为参数传递。

  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;
         }
   };

只能通过引用返回非本地对象。析构函数可能使某些内部指针无效,或者其他什么。

不要害怕返回值——它很快!

我将向您展示一些示例:

第一个例子,不返回本地作用域对象,例如:

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

不能通过引用返回local,因为localdontDoThis的主体末尾被销毁。

第二个示例,您可以通过引用返回:

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

在这里,您可以通过引用返回s1s2,因为它们是在调用shorterString之前定义的。

第三个例子:

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

使用代码如下:

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

get_val可以通过引用返回s的元素,因为s在调用之后仍然存在。

第四个例子

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;
}

用法示例:

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

第五个例子:

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;
}

然后你可以像这样使用上面的operator=

String a;
String b;
String c = b = a;

好吧,它在代码中可能不是一个非常漂亮的解决方案,但在函数的接口中确实很漂亮。而且它也非常高效。如果第二个对你来说更重要(例如,你正在开发一个库),这是理想的选择。

诀窍是:

  1. 一行A a = b.make();在内部转换为A的构造函数,也就是说,就像您编写了A a(b.make());一样
  2. 现在b.make()应该会产生一个带有回调函数的新类
  3. 这整件事只能由类来处理,而不需要任何模板

这是我的最简单的例子。只检查main(),因为您可以看到它很简单。内部不是。

从速度的角度来看:Factory::Mediator类的大小只有2个指针,大于1但不大于1。这是整个事物中唯一通过价值传递的对象。

#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 = %in", a.getV());
  return 0;
}

返回一个已启动的对象并不是很好的做法,因为它确实超出了范围。很少有这样的选择。如果类是一个引用计数智能指针或其他智能指针,则实际上可以这样做。引用计数智能指针';s的参考计数工作?