【问题标题】:Accessing a virtual member function of a template argument derived class in C++在 C++ 中访问模板参数派生类的虚拟成员函数
【发布时间】:2022-01-04 20:56:01
【问题描述】:

我可能只是忽略了某些事情或愚蠢,在这种情况下我很抱歉,但我真的不确定如何(如果可能的话)访问虚拟成员函数。实际上,虚拟部分是关于可能的解决方案的第二个问题,我将在后面描述。这是一些总结我的问题的示例代码:

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 中的覆盖函数。

我正在尝试做的事情可能像这样吗?

【问题讨论】:

  • 尝试返回 cT().ClassName();请注意该函数的返回类型为 void。所以它的 return 语句不应该返回一个表达式。
  • ClassName 不是静态成员。你需要一个类类型的对象来调用成员。
  • 一个minimal reproducible example 最好只产生您感到困惑的错误,包括预期的输出。上面的代码很混乱,很难说你在做什么。如果您的问题与模板有关,那么显示有效的等效非模板代码是一个不错的计划。

标签: c++ class templates


【解决方案1】:

对不起,如果我显得粗鲁,但你不能从 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;

Online Demo

当然,它也可以使用一些全局对象来代替(但模板的意义要小得多),或者更好的是,如果您将 StatusPrint() 重构为模板类的成员函数,则可以使用模板类中的对象.

【讨论】:

    【解决方案2】:

    我不确定你到底想做什么,但看看这是否更像它:

    std::string StatusPrint(BaseClass *instance) {
        return instance->ClassName();
    }
    

    模板参数用于类型,虚拟继承需要指针。

    DerivedClass derived;
    std::cout << StatusPrint(&derived) << std::endl; // note the &
    

    【讨论】:

      【解决方案3】:

      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();
            |            ^
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-01-05
        • 1970-01-01
        • 1970-01-01
        • 2017-11-27
        • 1970-01-01
        • 2014-08-01
        • 2018-09-18
        相关资源
        最近更新 更多