I might simply be overlooking something or being stupid, in which case I am sorry, but I'm really not sure how to, if it is even possible, access a virtual member function. Actually, the virtual part is a second issue about a possible solution I will describe later. Here's some example code that summarizes my issue:
class BaseClass
{
public:
virtual std::string ClassName()
{
return "BaseClass";
}
};
class DerivedClass : public BaseClass
{
public:
std::string ClassName()
{
return "DerivedClass";
}
};
template<class cT>
void StatusPrint(const std::string& message)
{
return cT.ClassName(); // Here's where my issue arises.
}
So, I tried to replace cT. with ct::, however, while that causes compiler issues on its own, it also tries to access the virtual function in BaseClass, but I want to access the overridden function in DerivedClass.
Is what I am trying to do possible like this?
CodePudding user response:
Sorry if I'd seem rude, but you cannot return anything from void function. So apparently, we don't have the full story here.
Do you really want a compile time solution?
Looking at your code, it seems that className() does not use at all the state of the object. So you could make it static (instead of virtual). THe problem would then be solved with:
template<class cT>
std::string StatusPrint(const std::string& message) // returns string, not void
{
return cT::ClassName(); // :: if class name is static.
}
Since the template cannot derive the type from its argument, you'd need to provide it, making the choice of the class completely compile-time:
cout<< StatusPrint<DerivedClass>("test"s)<<endl;
This kind of practice is used, when you have some utility classes and you want to configure at compile time which one to use.
Do you want a dynamic solution?
If you want a dynamic solution at runtime, you need to use some object, because virtual require an object that knows its dynamic type at runtime.
Then it depends on the context. One solution is to use a cT parameter, with the advantage of parameter deduction:
template<class cT>
std::string StatusPrint ( cT object, const std::string& message)
{
return object.ClassName(); // Here's where my issue arises.
}
You'd then call it:
DerivedClass test;
...
cout<< StatusPrint(test, "test"s)<<endl;
But of course, it could also use some global object instead (but the template makes then much less sense), or better, an object in a template class if you refactor StatusPrint() to be a member function of such a class.
CodePudding user response:
I'm not sure what exactly you are trying to do, but see if this is more like it:
std::string StatusPrint(BaseClass *instance) {
return instance->ClassName();
}
Template parameters are for types, virtual inheritance needs pointers.
DerivedClass derived;
std::cout << StatusPrint(&derived) << std::endl; // note the &
CodePudding user response:
cT is a type, not an object. You can only call functions on object instances (unless they're static functions, but that's not what you're trying to do here). You need to pass in an instance of the object you want to print out. e.g.
template<class T>
std::string StatusPrint(const T& obj, const std::string& message)
{
return obj.ClassName();
}
It's also customary to name template types with Uppercase to avoid this confusion.
I have to admit the compiler error for this is confusing, but it does give you a hint that there's something wrong with cT. It's saying that what comes before . is not what it was expecting.
With GCC 9:
error: expected primary-expression before '.' token
24 | return cT.ClassName();
| ^
