简体   繁体   中英

C++ pass by reference and this object

Why is answer "OK"?

class CTest {
public:
    int isitme(CTest& cobj);
};
int CTest::isitme(CTest &cobj)
{
    if(&cobj == this)
    {
        return true;
    }
    else
    {
        return false;
    }
}
int main()
{
    CTest a;
    CTest *b = &a;
    if(b->isitme(a))
    {
        cout<<"OK";
    }else
    {
        cout<<"not OK";
    }
    return 0;
}

Because a member function implicitly receives as an argument a pointer to the object it is invoked on. This pointer is made available within the body of the function as the this pointer.

So when you do:

b->isitme(a)

The member function isitme() implicitly receives the pointer b as an argument, and that pointer will be seen as the this pointer inside the function.

Since b points to a , this will point to a (after all, you are invoking the member function isitme() on object a through the pointer b ).

Since a is what is being passed as an explicit argument, a is also what the reference cobj is bound to. Therefore, taking the address of cobj gives you the address of a . Which in turns mean, that the expression:

//  Address of "a": "cobj" is bound to argument "a" in the function call
//  vvvvv
    &cobj == this
//           ^^^^ 
//           Address of "a": the function is called through a pointer to "a"

Evaluates to true .

The short answer is that b is a pointer to a -- they both refer to the same actual object, so when you compare those "two" objects' addresses, they compare equal.

There's something else that really needs to be pointed out, and although it's more comment than answer, it won't fit in a comment, so...

int CTest::isitme(CTest &cobj)
{
    if(&cobj == this)
    {
        return true;
    }
    else
    {
        return false;
    }
}

This is, quite honestly, pretty lousy code. Since it's really returning a bool , you should declare it to return a bool. It's also much better to directly return the result from the comparison. You should also do some reading about "const correctness". Taking those factors into account, your function ends up looking more like this:

bool CTest::isitme(CTest const &cobj) const {
    return this == &cobj;
}

There are a couple of things going on here.

First, there is only one copy of CTest being allocated. To check this, you could put a print in the constructor:

class CTest {
public:
  CTest() {
    cout << "Constructor called";
  }    
...
};

If you then invoked your program, you'd see that the constructor was called only once.

When isitme is invoked, the this pointer is being compared to the address of the cobj parameter. Both are pointing to the same object, so they both contain the same memory address. Thus, the comparison passes.

The other thing to notice is that you are passing by reference. If you didn't pass by reference, then this would not work. For example, if you had the following code:

class CTest {
public:
...
  bool isitme(CTest cobj) {
    return this == &cobj;
  }
};

Then the object would be passed by value. As a result, a copy of cobj is made. In fact, another constructor (the compiler provided default copy constructor) is called to make a new object which is a copy of the given one.

To prove this, override the default copy constructor to display a message.

class CTest {
public:
  // Default constructor
  CTest() {
    cout << "Constructor called" << endl;
  }
  // Copy constructor
  CTest(CTest& source) {
    cout << "Copy constructor called" << endl;
  }
  // Comparison
  bool isitme(CTest obj) {
    return (this == &obj);
  }
};

// Main program
int main (int argc, char* argv[]) {
  ...
  CTest a;
  CTest* b = &a;
  cout << (b->isitme(a)) << endl;
  ...
}

Now if you run the program, you'd notice both constructors are called. The first time is during the constructor for a . The second time is when you pass a to the isitme method and it creates a copy.

When passed by value, the isitme check would fail because it is comparing the pointers (memory addresses) of two different objects.

int CTest::isitme(CTest &cobj) 
{ 
    // cobj is a reference, but still an object
    CTest * pCobj = &cobj; //pCobj is now the pointer to the actual memory
    //so it's the same as this pointer. Because you did before CTest *b = &a;        
}

b is pointing a, then you are using a in

b->isitme(a)

the isitme() simply checks the object passed as parameter against this . In this case it is, so OK

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM