我可能只是忽略了什么或很愚蠢,在这种情况下我很抱歉,但我真的不知道如何访问虚拟成员函数(如果可能的话(。实际上,虚拟部分是关于可能的解决方案的第二个问题,我稍后将对此进行描述。以下是一些总结我的问题的示例代码:
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.
}
因此,我尝试用ct::
替换cT.
,然而,虽然这本身会导致编译器问题,但它也尝试访问BaseClass中的虚拟函数,但我想访问DerivedClass中的重写函数。
我想做的事情可能这样吗?
很抱歉我看起来很粗鲁,但您不能从void
函数返回任何内容。显然,我们这里没有完整的故事。
你真的想要一个编译时解决方案吗
查看您的代码,className()
似乎根本没有使用对象的状态。所以你可以把它做成static
(而不是virtual
(。这个问题可以通过来解决
template<class cT>
std::string StatusPrint(const std::string& message) // returns string, not void
{
return cT::ClassName(); // :: if class name is static.
}
由于模板无法从其参数派生类型,因此您需要提供它,以便在编译时完全选择类:
cout<< StatusPrint<DerivedClass>("test"s)<<endl;
当您有一些实用程序类,并且希望在编译时配置要使用哪一个时,就会使用这种做法。
您想要动态解决方案吗
如果您希望在运行时使用动态解决方案,则需要使用一些对象,因为virtual
需要一个在运行时知道其动态类型的对象。
然后它取决于上下文。一种解决方案是使用cT
参数,具有参数推导的优点:
template<class cT>
std::string StatusPrint ( cT object, const std::string& message)
{
return object.ClassName(); // Here's where my issue arises.
}
然后你可以称之为:
DerivedClass test;
...
cout<< StatusPrint(test, "test"s)<<endl;
在线演示
当然,它也可以使用一些全局对象(但模板的意义要小得多(,或者更好的是,如果您将StatusPrint((重构为此类的成员函数,则可以使用模板类中的对象。
我不确定你到底想做什么,但看看这是否更像:
std::string StatusPrint(BaseClass *instance) {
return instance->ClassName();
}
模板参数用于类型,虚拟继承需要指针。
DerivedClass derived;
std::cout << StatusPrint(&derived) << std::endl; // note the &
cT
是一种类型,而不是对象。您只能在对象实例上调用函数(除非它们是静态函数,但这不是您在这里要做的(。您需要传入要打印出的对象的实例。例如
template<class T>
std::string StatusPrint(const T& obj, const std::string& message)
{
return obj.ClassName();
}
为了避免这种混淆,通常使用大写字母命名模板类型。
我不得不承认编译器的错误让人困惑,但它确实给了你一个暗示,cT
有问题。这是说.
之前发生的事情并不是它所期望的。
与GCC 9:
error: expected primary-expression before '.' token
24 | return cT.ClassName();
| ^