Unable to assign method pointer from inherited class

I have this two classes:

class IBaseA { public: virtual bool sayHello(std::string&) = 0; ~IBaseA(){} }; class BaseA: public IBaseA { public: virtual bool sayHello(std::string &str) { std::cout << "Hello " << str << std::endl; return (true); } BaseA(){} }; 

Can you explain to me why I cannot do something like this

 bool (IBaseA::*ptr)(std::string&) = &BaseA::sayHello; 

error: cannot convert 'bool (BaseA: :) (std :: string &) {aka bool (BaseA: :) (std :: basic_string &)}' to 'bool (IBaseA: :) (std :: string &) {aka bool (IBaseA: :) (std :: basic_string &)} 'during initialization

I do not understand why I can not do something like this.

But if I changed the destination to

 bool (IBaseA::*ptr)(std::string&) = &IBaseA::sayHello; 

then I can use this pointer without problems

 BaseA A; (A.*ptr)(str); 

edit: Thanks for the answers, I thought that since all the addresses are in the vtable, they are the same location according to what I understood from wikipedia.

+4
source share
4 answers

Member pointer conversions work against normal pointer conversions. You can convert a pointer to a derived class to a pointer to a base class, but not vice versa. You can convert a pointer-to-member of a base class to a member-pointer of a derived class, but not vice versa.

Always think whether the conversion really is.

Regular pointers: all BaseA instances are IBaseA instances, so conversion is legal. Not all IBaseA instances are IBaseA instances, so you cannot convert another way.

Member Pointers: All IBaseA members IBaseA also present in BaseA , so you can convert a pointer to an IBaseA element to a pointer to a BaseA element. However, not all BaseA members BaseA present in IBaseA , so conversion to the other side is not possible.

+5
source

Given the two pointer-member types T C1::*P1 and T C2::*P2 (where T can be a function type), you can only convert P1 to P2 if C2 is derived from C1. Note that this is an inverse of pointers to objects where you can only pump.

The reason is that if you have a pointer to a member of a base class, any subclass, as guaranteed, also has that member, since it inherited it. Another method does not apply.

This is a basic type conversion rule. This does not change just because this particular pointer that you do there is an override of the virtual function existing in the base class.

+1
source

The real answer is probably "because the language specification says you cannot", however think about what you are trying to do:

 bool (IBaseA::*ptr)(std::string&) = &BaseA::sayHello; 

Essentially, it reads like: I want the ptr variable, which is a pointer to an IBaseA member function, and I want it to point to the sayHello method in BaseA.

Yes, the sayHello method in BaseA overrides the value in IBaseA, but they are still different methods. Imagine if you tried to use a pointer to call a method on an object of type IBaseA, which was not actually BaseA - this is syntactically allowed, but what do you expect?

In other words, taking a pointer to a member of a derived class and assigning it to a variable declared a dot in a member of the base class will violate the security of the static type.

+1
source

Although this may seem contradictory, you cannot convert a pointer-to-member of a derived type to a member-to-base binding. Correct conversion is the other way around: you can convert a member-to-member to a base with a member-pointer to a derived one.

The reason is that the derived type is guaranteed to have this element if the base has it, but the other path around it is incorrect (i.e., a pointer to a member of the derived type may refer to an element that has been added and is not present in the database).

Another thing you can miss is that member pointer functions are polymorphic, meaning you can store &IBase::sayHello and call Base::sayHello if the member to which it is applied is of type Base .

+1
source

Source: https://habr.com/ru/post/1487467/


All Articles