Calling a virtual member function from a base class (template)

Suppose I have the following:

#include <iostream> #include <string> template<class T> class base { public: void print() { T t = get(); std::cout << t << std::endl; } virtual T get() const { // assumes T can be constructed from, say, -1 T t = -1.0; return t; } }; class derived : public base<std::string> { public: virtual std::string get() const { // this is a silly example, but one can // imagine that what we return here could // depend on data members of derived return "this is a string"; } }; int main() { derived d; d.print(); return 0; } 

It seems to me that d.print() should call derived::get() , because get() is virtual. However, I get a compiler error saying that I cannot initialize string to -1.0 , which means that the compiler is trying to call base::get() when d.print() called. What's happening?

+4
source share
4 answers

However, I get a compiler error saying that I cannot initialize the string to -1.0, which means that the compiler is trying to call base :: get () when I call d.print ().

No, this compiler error means that the compiler is trying to create an instance of base<std::string>::get() , which it must execute because derived uses base<std::string> as the base class. Just because you are not calling a function does not mean you cannot. You can still call base<std::string>::get() directly.

You created an instance of base<std::string> and used it as a base class. Since base<std::string>::get() is a virtual function, it is considered "used" because you use base<std::string> as a base class. Since it is used, it must be created. Therefore, the compiler should and will try to compile the function.

And since std::string cannot be implicitly built from float, compiler errors occur due to a failed template replacement.

+6
source

If you implicitly create an instance of a class template, only those member functions will be created that will be used, as you already know, or else you will not ask about it. The problem is that the definition of use in the standard may not be exactly what you expect, and in particular, any virtual function is used if it is not clean

§3.2p2 [...] A virtual member function is used by odr if it is not pure. [...]

And this means that base::get used even if your code does not explicitly call it, and thus the compiler implicitly creates an instance of it and throws the compiler error you see.

+4
source
 T t = -1.0; 

Of course, this does not compile if T is std::string . It has nothing to do with get virtual and what function will be called at runtime. Runtime appears after the code is compiled into machine code, and your code will not even compile.

Why don't you do it:

 T t = T(); 

Again, T needs to have a default constructor.

+1
source

The problem is this method (where T = std :: string):

 virtual T get() const { // assumes T can be constructed from, say, -1 T t = -1.0; return t; } 

The compiler is right. You cannot initialize std :: string with a double value.

+1
source

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


All Articles