我试图允许一个子类定义可变参数函数的特化。 例如:
#include <iostream>
#include <vector>
#include <memory>
class BaseClass
{
public:
BaseClass() {};
virtual ~BaseClass() {};
template<typename GenericData>
void ReceiveData(GenericData &inData)
{
throw std::runtime_error("Undefined");
}
};
class ReceiveInt : public BaseClass
{
void ReceiveData(int & inData)
{
std::cout << "I know what to do!";
}
};
int main(int argc, char* argv[])
{
std::vector<std::shared_ptr<BaseClass>> classHolder;
classHolder.push_back(std::make_shared<ReceiveInt>());
int test = 1;
classHolder.front()->ReceiveData(test);
return 0;
}
但不幸的是,这不起作用,因为调用了 BaseClass ReceiveData 函数。 这可能吗?
编辑 1正如人们所指出的,我的符号非常错误。 看起来我今天学到的比我预期的要多。
这可能吗?
我不这么认为。
动态调度仅适用于virtual
成员函数。
成员函数模板可能不virtual
。
如果可以使用常规成员函数,即不使用成员函数模板,则可以使它们virtual
。那会起作用。
你在这里混淆了一些概念。
首先,这里没有可变参数模板ReceiveData
如下函数:
template<typename GenericData>
void ReceiveData(GenericData &inData)
{
throw std::runtime_error("Undefined");
}
是一个模板成员函数。
然后,如果要重写派生类中的方法,正确的方法是使用虚函数,可能是基类中的纯虚函数和派生类中具有重写说明符的虚函数。
但是,virtual
函数将您限制为一组固定类型,因为没有模板虚拟函数。不过,您可以尝试使用 CRTP
template<typename T>
class Base {
public:
void receiveData(const T&) {}
};
class ReceiveInt : public Base<int> {};
它模拟了一种静态多态性。下面:
ReceiveInt{}.receiveData(int{});
从使用 int
实例化的基类中receiveData
。
我认为您可能会混淆您的术语。 BaseClass::ReceiveData
是一种模板化方法,采用模板参数GenericData
。可变参数函数接受在运行时确定的许多参数。
在ReceiveInt
中,你没有对任何东西进行专业化,因为ReceiveInt::ReceiveData
不是一个模板化的方法。事实上,即使它是模板化的,也无法调用您的示例。指向BaseClass
的指针如何知道如何在其指向的派生类中调用模板专用化?
你可以做BaseClass::ReceiveData
virtual
.这允许您在基类中重写它,并且仍然使用指向 BaseClass
的指针调用它。不幸的是,模板是编译时语言功能,而动态调度是运行时功能——在这种情况下,您不能同时拥有两者。
引用
-
可变参数函数
-
模板专业化
-
为什么我们在C++中需要虚拟功能?
您必须先强制转换为派生类型,无法使用基类指针/引用,因为基类只知道自己的实现。这甚至不是可以对派生类型使用递归依赖项的情况,因为在实例化基时尚未定义派生类型。
如果强制转换为派生类型,则它将能够根据需要解析派生成员。
您的代码中没有可变参数模板,就像其他人已经解释的那样。但是,您可以使用模板化类方法在首次调用时实例化的事实。但是这里没有虚拟覆盖。在此示例中,您可以在 Base 类和派生类中定义方法模板的不同实现,但您必须明确告知编译器要使用哪一个。如果没有显式强制转换,则无法通过基类指针使用派生类方法:
#include <iostream>
#include <memory>
using namespace std;
class Base
{
public:
Base() {};
virtual ~Base() {};
template<typename T>
void ReceiveData(T)
{
throw std::runtime_error("Undefined");
}
};
class Derived : public Base
{
public:
template<typename... Args >
void ReceiveData(Args... args)
{
(void)std::initializer_list<int>{(std::cout << args << std::endl, 0)...};
}
};
int main()
{
Base b;
// b.ReceiveData(1); //-> this calls base class method
Derived d;
d.ReceiveData(1); // this calls the method in the derived class
d.ReceiveData(2, "hello"); // this calls the method in the derived class
Base* b2 = new Derived();
// b2->ReceiveData(3); // this will instantiate and call the base class method
// thus raising an exception
// because no virtual overriding of templated methods
((Derived*)b2)->ReceiveData("world",1); // this will instantiate and call the derived class
// method, then because of explicit casting the
// compiler knows which class to target
return 0;
}
现场演示:https://wandbox.org/permlink/K0qEAC7C7yzg6gYL