Pass a pointer to a derived class pointer as a parameter to a constructor expecting a pointer to a base class pointer

你离开我真会死。 提交于 2019-12-11 19:27:43

问题


I've read

  • Passing pointer to derived class, to function that expects pointer to base class?

but the answer doesn't seem applicable to my issue.

I checked via Ideone that the following compiles, as it should:

class Base
{
public:
    Base() {}
    virtual ~Base() {}
};

class Derived : public Base
{
public:
    Derived() {}
    virtual ~Derived() {}
};

class Manager
{
public:
    Manager(Base* b) {}
    ~Manager() {}
private:
    Manager() {}
};

int main()
{
    Derived* d = new Derived;
    Manager* m = new Manager(d);
    return 0;
}

However, what I believe is the same scenario in my actual program, produces an error (keywords have been replaced of course):

"main.cc", line 551: Error: Could not find a match for Manager::Manager(Derived*) needed in main().

I realize that posting explicit code would help, but the complexity of the code (not written by me, involving countless layers of inheritance, tens of includes per file, friend classes everywhere, extern'ed variables, etc.) is mind-numbing, and I'm not even sure what to reduce (what is relevant and what is not) to obtain something reasonable to post here.

I have one hint that may help. I found that casting to the base class beforehand works:

Manager* m = new Manager((Base*)d);

Of course, I shouldn't have to do that. But the fact that that works tells me that I haven't made some trivial mistake like forgetting a * in the constructor's signature.

Can anyone think of some possible reasons I could be getting the error that I'm getting, but not when I explicitly cast the derived instance to the base class?

I'm using Sun Studio 12 Update 1.


Additional Details

I don't know why this would matter, but in my real application I'm working with pointer pointers, e.g.

...

class Manager
{
public:
    Manager(Base** b) {}
    ~Manager() {}
private:
    Manager() {}
};

...

    Derived* d = new Derived;
    Derived** d_ptr = &d;
    Manager* m = new Manager(&d_ptr);

So, to reiterate, the above works when I do the following.

    Manager* m = new Manager((Base**)(&d));

回答1:


Consider the following minimal example:

struct Base {};

struct Derived {};

int main()
{
    Derived** ppD;
    Base** ppB = ppD; // (A)
}

This code does not compile, because there's no implicit conversion in the line (A) to convert from Derived** to Base**. [conv.ptr]/3

A prvalue of type “pointer to cv D”, where D is a class type, can be converted to a prvalue of type “pointer to cv B”, where B is a base class of D. If B is an inaccessible or ambiguous base class of D, a program that necessitates this conversion is ill-formed.

This means that the conversion Base* pB = *ppD; is well-formed, but there's no implicit conversion for the case in line (A). Problems could occur if it was legal for example for multiple inheritance, virtual inheritance, or any other situation where the address of a pointer to an object of Derived has to be adjusted to get a pointer to the subobject of type Base.

Also consider the following scenario:

void f(Base** p)
{
    delete *p;
    *p = new Base;
}

int main()
{
    Derived* pDerived = new Derived;
    f(&p); // imagine this was allowed
    // pDerived now points to an object of type Base!
}



回答2:


Implicit conversion from pointer-to-derived to pointer-to-base does not extend to pointer-to-pointer-to-derived. You would get the same error if you tried this:

struct Base{};
struct Derived: Base {};

void f(Base **p){}

int main()
{
    Derived *dp = 0;
    f( &dp);
}



回答3:


The following code will compile and work as the 'Derived' class is derived from the 'Base' class.

class Base
{
public:
    Base() {}
    virtual ~Base() {}
};

class Derived : public Base
{
public:
    Derived() {}
    virtual ~Derived() {}
};

class Manager
{
public:
    Manager(Base* b) {}
    ~Manager() {}
private:
    Manager() {}
};

int main()
{
    Derived* d = new Derived;
    Manager* m = new Manager(d);
    return 0;
}

However, a pointer to a pointer to a 'Derived' class is not the same as (nor derived from) a pointer to a pointer to a 'Base' class.

For a great explanation involving bowls of bananas and apples, look here: Conversion from Derived** to Base**

HTH.




回答4:


Do either

Derived* d = new Derived;
Derived** d_ptr = &d;
Manager* m = new Manager(*d_ptr);

or

Derived* d = new Derived;
Derived** d_ptr = &d;  // not needed ?
Manager* m = new Manager(d);


来源:https://stackoverflow.com/questions/18098788/pass-a-pointer-to-a-derived-class-pointer-as-a-parameter-to-a-constructor-expect

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!