J'ai une classe appelée Object qui stocke des données.
Je voudrais le renvoyer par référence en utilisant une fonction comme celle-ci:
Object& return_Object();
Ensuite, dans mon code, je l'appellerais comme ceci:
Object myObject = return_Object();
J'ai écrit du code comme celui-ci et il se compile. Cependant, lorsque j'exécute le code, j'obtiens systématiquement une erreur de segmentation. Quelle est la bonne façon de renvoyer un objet classe par référence?
Vous retournez probablement un objet qui est sur la pile. Autrement dit, return_Object()
ressemble probablement à ceci:
Object& return_Object()
{
Object object_to_return;
// ... do stuff ...
return object_to_return;
}
Si c'est ce que vous faites, vous n'avez pas de chance - object_to_return
est hors de portée et a été détruit à la fin de return_Object
, donc myObject
fait référence à un objet inexistant. Vous devez soit renvoyer par valeur, soit renvoyer un Object
déclaré dans une portée plus large ou new
ed sur le tas.
Vous ne pouvez utiliser que
Object& return_Object();
si l'objet renvoyé a une portée plus grande que la fonction. Par exemple, vous pouvez l'utiliser si vous avez une classe où elle est encapsulée. Si vous créez un objet dans votre fonction, utilisez des pointeurs. Si vous souhaitez modifier un objet existant, passez-le comme 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;
}
};
Vous ne pouvez renvoyer des objets non locaux que par référence. Le destructeur peut avoir invalidé un pointeur interne ou autre.
N'ayez pas peur de renvoyer des valeurs - c'est rapide !
Eh bien, ce n'est peut-être pas une très belle solution dans le code, mais c'est vraiment beau dans l'interface de votre fonction. Et c'est aussi très efficace. Elle est idéale si la seconde est plus importante pour vous (par exemple, vous développez une bibliothèque).
L'astuce est la suivante:
A a = b.make();
est convertie en interne en un constructeur de A, c'est-à-dire comme si vous aviez écrit A a(b.make());
.b.make()
devrait produire une nouvelle classe, avec une fonction de rappel.Voici mon exemple minimal. Ne cochez que la main()
, comme vous pouvez le voir, c'est simple. Les internes ne le sont pas.
Du point de vue de la vitesse: la taille d'un Factory::Mediator
classe n'est que de 2 pointeurs, ce qui est plus que 1 mais pas plus. Et c'est le seul objet de l'ensemble qui soit transféré par la valeur.
#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;
}
Je vais vous montrer quelques exemples:
const string &mainip(const string &s)
{
string ret=s;
// operator ret
return ret;
}
vous ne pouvez pas retourner ret par référence, car ret est détruit à la fin.
const string &shorterString(const string &s1,const string &s2)
{
return s1.size()<s2.size()?s1:s2;
}
vous pouvez retourner par référence pour s1 et s2 est toujours existant.
char &get_val(string &str,string::size_type ix)
{
return str[ix];
}
code d'utilisation comme ci-dessous:
string s("123456");
cout<<s<<endl;
char &ch = get_val(s,0);
ch ='A';
cout<<s<<endl; // A23456
car après retour par référence, l'objet existe toujours;
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;
}
exemple d'utilisation:
Student stu;
stu.m_name = 'jack';
string name = stu.getName(); //
//or
string name2 = Test(stu);
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;
}