简体   繁体   中英

How to pass pointer of derived class to reference to pointer of base class?

Here is the sample code.

class BaseClass {
};

class DerivedClass : public BaseClass {
};

int Foo(BaseClass*& ptr) {
}

DerivedClass* ptr_to_derived;

//following will not work
Foo(ptr_to_derived);

I fail to compile code above, and the error message is " can't convert DerivedClass* to BaseClass*& ". So How can I pass ptr_to_derived to Foo?

The error message is quite clear:

error: invalid initialization of non-const reference of type ' BaseClass*& ' from an rvalue of type ' BaseClass* '

Because Foo takes a pointer by non-const reference you can't pass it an rvalue. The implicit conversion from DerivedClass to BaseClass that happens when you pass it to Foo gets you the rvalue that the error is complaining about.

You can create a base pointer from the derived one and pass that:

DerivedClass* ptr_to_derived;
BaseClass* ptr_derived_base = ptr_to_derived;

Foo(ptr_derived_base);

You cannot do that.

What you can do is convert to a pointer to a base, store that converted pointer somewhere (such as variable), and pass that by lvalue reference. The reference cannot refer to the derived pointer. Like so:

BaseClass* ptr_to_base = ptr_to_derived;
Foo(ptr_to_base);

However, it would be better to pass the pointer by value in order to avoid this hassle. Or preferably even pass a reference instead of a pointer to the base in case that is sufficient. Like so:

int Foo(BaseClass& ref)

With this you can call:

DerivedClass1 d1;
DerivedClass2 d2;
Foo(d1);
Foo(d2);

// or with pointers
DerivedClass1* d1_ptr = &d1;
DerivedClass2* d2_ptr = &d2;
Foo(*d1_ptr);
Foo(*d2_ptr);

The problem is that Foo might modify the passed pointer-to-base. For example:

class OtherDerivedClass : public BaseClass {
};

OtherDerivedClass* ptr_to_other_derived = ...;

void Foo(BaseClass*& ptr)
{
    ptr = ptr_to_other_derived;
}

What do you think should happen if you could call this Foo with ptr_to_derived ? Should ptr_to_derived now point not to a DerivedClass but to an OtherDerivedClass object? That's wrong on every level.

Solution 1: Don't allow Foo to modify the pointer. Either pass by value:

void Foo(BaseClass* ptr)

or by const-ref:

void Foo(const BaseClass*& ptr)

Solution 2: Create a pointer-to-base variable that Foo can modify.

BaseClass* ptr_to_base = ptr_to_derived;
foo(ptr_to_base);

This will of course leave ptr_to_derived unmodified. C++ does not let you pass a temporary expression (which is what the conversion from DerivedClass* to BaseClass* would return) because, again, Foo says it will modify that pointer and the changed temporary would just be discarded. That's usually a mistake. You could of course still decide to not care about the change to ptr_to_base that Foo might make.

This is illegal for good reasons, look at following code:

class BaseClass {};

class DerivedClass :public BaseClass {};
class DerivedClass2 :public BaseClass {};

DerivedClass2 derived2;

void Foo(BaseClass*& ptr) {
    ptr = &derived2; // Legal.
}

DerivedClass* ptr_to_derived = nullptr;

then if legal, Foo(ptr_to_derived) would make ptr_to_derived to unrelated DerivedClass2 which is wrong.

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