C++ 如何使用模板化函数实现多态性?
在我的项目中,我有一个带有接口的基本抽象类,派生类实现了接口。这些派生类具有接受不同类型参数的泛型函数。我使用函数模板在派生类中编写了这些泛型函数 我想将这些模板函数添加到基类的接口中。所以我可以实现多态性:在其他函数中接受基类,并在派生类中调用这些模板化函数 当我们使用普通函数时,我们会执行虚函数和重写,但不能使用模板函数执行虚函数 我试图在我的抽象基类中使用纯抽象模板函数,但它不起作用C++ 如何使用模板化函数实现多态性?,c++,abstract-class,function-templates,C++,Abstract Class,Function Templates,在我的项目中,我有一个带有接口的基本抽象类,派生类实现了接口。这些派生类具有接受不同类型参数的泛型函数。我使用函数模板在派生类中编写了这些泛型函数 我想将这些模板函数添加到基类的接口中。所以我可以实现多态性:在其他函数中接受基类,并在派生类中调用这些模板化函数 当我们使用普通函数时,我们会执行虚函数和重写,但不能使用模板函数执行虚函数 我试图在我的抽象基类中使用纯抽象模板函数,但它不起作用 这是一个小程序,具有我试图实现的功能,但由于virtual您试图使用声明为virtual的方法模板,因此无
这是一个小程序,具有我试图实现的功能,但由于
virtual您试图使用声明为virtual
的方法模板,因此无法编译。这是不可能的。另请参见相关问题
似乎您正在尝试创建某种序列化/反序列化机制。您希望将不同的结构(在不同的类中实现)转换为字节,并希望能够通过以某种方式解释字节来重新创建正确类型的对象
让我们首先处理序列化问题。通过为所有结构定义一个接口,并使用每个结构都应实现的序列化方法,您可以轻松解决此问题:
class Structure
{
public:
virtual std::vector<uint8_t> ToBytes() = 0;
// any other functionality common to all structures
};
希望这能有所帮助。以下是我试图实现的行为的C版本:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace baseAbstractTemplates.NET {
interface IObjectTransformer {
TStructure ToStructure<TStructure>(ICollection<byte> bytes);
ICollection<byte> ToBytes<TStructure>(TStructure structure);
};
class ObjectTransformer1 : IObjectTransformer {
#region Implementation of IObjectTransformerBaseAbstractClass
public TStructure ToStructure<TStructure>(ICollection<byte> bytes) {
throw new NotImplementedException();
}
public ICollection<byte> ToBytes<TStructure>(TStructure structure) {
throw new NotImplementedException();
}
#endregion
}
class ObjectTransformer2 : IObjectTransformer {
#region Implementation of IObjectTransformerBaseAbstractClass
public TStructure ToStructure<TStructure>(ICollection<byte> bytes) {
throw new NotImplementedException();
}
public ICollection<byte> ToBytes<TStructure>(TStructure structure) {
throw new NotImplementedException();
}
#endregion
}
class Program {
public static void CoutStructureBytes(IObjectTransformer objectTransformer) {
var bytes = objectTransformer.ToBytes(3);
Console.WriteLine(bytes);
}
static void Main(string[] args) {
ObjectTransformer1 objectTransformer1 = new ObjectTransformer1();
ObjectTransformer2 objectTransformer2 = new ObjectTransformer2();
CoutStructureBytes(objectTransformer1);
CoutStructureBytes(objectTransformer2);
}
}
}
// bastAbstractTemplates.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <vector>
#include <string>
template<typename DerivedClass>
class IObjectTransformer {
public:
template<typename TStructure> TStructure ToStructure(std::vector<unsigned char> bytes);
template<typename TStructure> std::vector<unsigned char> ToBytes(TStructure structure);
private:
IObjectTransformer() = default;
friend DerivedClass;
};
template <typename DerivedClass>
template <typename TStructure>
TStructure IObjectTransformer<DerivedClass>::ToStructure(std::vector<unsigned char> bytes) {
return static_cast<DerivedClass*>(this)->ToStructure(bytes);
}
template <typename DerivedClass>
template <typename TStructure>
std::vector<unsigned char> IObjectTransformer<DerivedClass>::ToBytes(TStructure structure) {
return static_cast<DerivedClass*>(this)->ToBytes(structure);
}
class ObjectTransformer1 : public IObjectTransformer<ObjectTransformer1> {
public:
template <typename TStructure> TStructure ToStructure(std::vector<unsigned char> bytes) {
unsigned char* bytePointer = &bytes[0];
TStructure structure = reinterpret_cast<TStructure>(*bytePointer);
return structure;
}
template <typename TStructure> std::vector<unsigned char> ToBytes(TStructure structure) {
char* bytesArray = reinterpret_cast<char*>(&structure);
auto byteVec = std::vector<unsigned char>(bytesArray, bytesArray + sizeof(TStructure));
return byteVec;
}
};
class ObjectTransformer2 : public IObjectTransformer<ObjectTransformer2> {
public:
template <typename TStructure> TStructure ToStructure(std::vector<unsigned char> bytes) {
TStructure structure{};
std::memcpy(&structure, &bytes[0], sizeof(TStructure));
return structure;
}
template <typename TStructure>
std::vector<unsigned char> ToBytes(TStructure structure) {
std::vector<unsigned char> bytes{};
bytes.resize(sizeof(TStructure));
std::memcpy(&bytes[0], &structure, sizeof(TStructure));
return bytes;
}
};
template <typename DerivedClass, typename TStructure>
void CoutStructureBytes(IObjectTransformer<DerivedClass> *objectTransformerBaseAbstractClass, TStructure structure) {
auto bytes = objectTransformerBaseAbstractClass->template ToBytes<TStructure>(structure);
for(auto byte : bytes) {
std::cout << std::to_string(byte) << ' ';
}
std::cout << std::endl;
}
int main() {
ObjectTransformer1 objectTransformer1{};
ObjectTransformer1 objectTransformer2{};
int integer = 5;
float someFloat = 9.79f;
CoutStructureBytes(&objectTransformer1, integer);
CoutStructureBytes(&objectTransformer2, someFloat);
}
在C#中,它只适用于“哈哈C#接口、模板、多态性go brrr”风格。即使你对C语言不熟悉,但有C++知识,我相信你可以遵循C代码。
这可以很好地编译和运行,并抛出NotImplementedException,因为它没有实现
<>但是,在C++中,与C语言不同,我不能仅仅使用通常的工具与模板、继承和多态进行接口:纯抽象函数(在派生类中重写)、模板、继承和方法重写。因为我不能将方法模板与虚拟模板混合使用
经过几天的研究,我终于发现了这一点:
[^]
CRTP和静态多态性。最后,C++版本的我试图实现的行为:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace baseAbstractTemplates.NET {
interface IObjectTransformer {
TStructure ToStructure<TStructure>(ICollection<byte> bytes);
ICollection<byte> ToBytes<TStructure>(TStructure structure);
};
class ObjectTransformer1 : IObjectTransformer {
#region Implementation of IObjectTransformerBaseAbstractClass
public TStructure ToStructure<TStructure>(ICollection<byte> bytes) {
throw new NotImplementedException();
}
public ICollection<byte> ToBytes<TStructure>(TStructure structure) {
throw new NotImplementedException();
}
#endregion
}
class ObjectTransformer2 : IObjectTransformer {
#region Implementation of IObjectTransformerBaseAbstractClass
public TStructure ToStructure<TStructure>(ICollection<byte> bytes) {
throw new NotImplementedException();
}
public ICollection<byte> ToBytes<TStructure>(TStructure structure) {
throw new NotImplementedException();
}
#endregion
}
class Program {
public static void CoutStructureBytes(IObjectTransformer objectTransformer) {
var bytes = objectTransformer.ToBytes(3);
Console.WriteLine(bytes);
}
static void Main(string[] args) {
ObjectTransformer1 objectTransformer1 = new ObjectTransformer1();
ObjectTransformer2 objectTransformer2 = new ObjectTransformer2();
CoutStructureBytes(objectTransformer1);
CoutStructureBytes(objectTransformer2);
}
}
}
// bastAbstractTemplates.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <vector>
#include <string>
template<typename DerivedClass>
class IObjectTransformer {
public:
template<typename TStructure> TStructure ToStructure(std::vector<unsigned char> bytes);
template<typename TStructure> std::vector<unsigned char> ToBytes(TStructure structure);
private:
IObjectTransformer() = default;
friend DerivedClass;
};
template <typename DerivedClass>
template <typename TStructure>
TStructure IObjectTransformer<DerivedClass>::ToStructure(std::vector<unsigned char> bytes) {
return static_cast<DerivedClass*>(this)->ToStructure(bytes);
}
template <typename DerivedClass>
template <typename TStructure>
std::vector<unsigned char> IObjectTransformer<DerivedClass>::ToBytes(TStructure structure) {
return static_cast<DerivedClass*>(this)->ToBytes(structure);
}
class ObjectTransformer1 : public IObjectTransformer<ObjectTransformer1> {
public:
template <typename TStructure> TStructure ToStructure(std::vector<unsigned char> bytes) {
unsigned char* bytePointer = &bytes[0];
TStructure structure = reinterpret_cast<TStructure>(*bytePointer);
return structure;
}
template <typename TStructure> std::vector<unsigned char> ToBytes(TStructure structure) {
char* bytesArray = reinterpret_cast<char*>(&structure);
auto byteVec = std::vector<unsigned char>(bytesArray, bytesArray + sizeof(TStructure));
return byteVec;
}
};
class ObjectTransformer2 : public IObjectTransformer<ObjectTransformer2> {
public:
template <typename TStructure> TStructure ToStructure(std::vector<unsigned char> bytes) {
TStructure structure{};
std::memcpy(&structure, &bytes[0], sizeof(TStructure));
return structure;
}
template <typename TStructure>
std::vector<unsigned char> ToBytes(TStructure structure) {
std::vector<unsigned char> bytes{};
bytes.resize(sizeof(TStructure));
std::memcpy(&bytes[0], &structure, sizeof(TStructure));
return bytes;
}
};
template <typename DerivedClass, typename TStructure>
void CoutStructureBytes(IObjectTransformer<DerivedClass> *objectTransformerBaseAbstractClass, TStructure structure) {
auto bytes = objectTransformerBaseAbstractClass->template ToBytes<TStructure>(structure);
for(auto byte : bytes) {
std::cout << std::to_string(byte) << ' ';
}
std::cout << std::endl;
}
int main() {
ObjectTransformer1 objectTransformer1{};
ObjectTransformer1 objectTransformer2{};
int integer = 5;
float someFloat = 9.79f;
CoutStructureBytes(&objectTransformer1, integer);
CoutStructureBytes(&objectTransformer2, someFloat);
}
“接受不同类型的参数”vs“而不使用模板”。???提示:请将代码简化为一个仅显示问题所在的示例。示例方法中的所有内容实际上只是在浪费读者的时间。一个简单的打印就足够了!请删除所有memcpy/resize,bla的东西,因为它实际上与具有未知参数类型的抽象基类无关…@Klaus好的,我将示例简化为只包含基类和派生类,不包含实现。我理解不可能同时使用模板和虚函数。这就是我试图解决问题的方法,但失败了。我确信我的问题有一个解决方案,也有可能解决我的问题,但在这种情况下,我不能同时使用模板和虚拟函数。我更仔细地了解了您试图实现的目标,并编辑了我的答案,以得出一个可能的解决方案。感谢您不厌其烦地编写此示例。不过,我的序列化示例只是一个示例。我在使用模板化方法实现多态性和继承以减少代码重复之后,序列化示例只是一个示例。请看我的答案:stackoverflow.com/a/62802439/6693304我自己写了这段代码,但我想我会习惯的。
static TypedStructureBuilder<SomeStructure> builder;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace baseAbstractTemplates.NET {
interface IObjectTransformer {
TStructure ToStructure<TStructure>(ICollection<byte> bytes);
ICollection<byte> ToBytes<TStructure>(TStructure structure);
};
class ObjectTransformer1 : IObjectTransformer {
#region Implementation of IObjectTransformerBaseAbstractClass
public TStructure ToStructure<TStructure>(ICollection<byte> bytes) {
throw new NotImplementedException();
}
public ICollection<byte> ToBytes<TStructure>(TStructure structure) {
throw new NotImplementedException();
}
#endregion
}
class ObjectTransformer2 : IObjectTransformer {
#region Implementation of IObjectTransformerBaseAbstractClass
public TStructure ToStructure<TStructure>(ICollection<byte> bytes) {
throw new NotImplementedException();
}
public ICollection<byte> ToBytes<TStructure>(TStructure structure) {
throw new NotImplementedException();
}
#endregion
}
class Program {
public static void CoutStructureBytes(IObjectTransformer objectTransformer) {
var bytes = objectTransformer.ToBytes(3);
Console.WriteLine(bytes);
}
static void Main(string[] args) {
ObjectTransformer1 objectTransformer1 = new ObjectTransformer1();
ObjectTransformer2 objectTransformer2 = new ObjectTransformer2();
CoutStructureBytes(objectTransformer1);
CoutStructureBytes(objectTransformer2);
}
}
}
// bastAbstractTemplates.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <vector>
#include <string>
template<typename DerivedClass>
class IObjectTransformer {
public:
template<typename TStructure> TStructure ToStructure(std::vector<unsigned char> bytes);
template<typename TStructure> std::vector<unsigned char> ToBytes(TStructure structure);
private:
IObjectTransformer() = default;
friend DerivedClass;
};
template <typename DerivedClass>
template <typename TStructure>
TStructure IObjectTransformer<DerivedClass>::ToStructure(std::vector<unsigned char> bytes) {
return static_cast<DerivedClass*>(this)->ToStructure(bytes);
}
template <typename DerivedClass>
template <typename TStructure>
std::vector<unsigned char> IObjectTransformer<DerivedClass>::ToBytes(TStructure structure) {
return static_cast<DerivedClass*>(this)->ToBytes(structure);
}
class ObjectTransformer1 : public IObjectTransformer<ObjectTransformer1> {
public:
template <typename TStructure> TStructure ToStructure(std::vector<unsigned char> bytes) {
unsigned char* bytePointer = &bytes[0];
TStructure structure = reinterpret_cast<TStructure>(*bytePointer);
return structure;
}
template <typename TStructure> std::vector<unsigned char> ToBytes(TStructure structure) {
char* bytesArray = reinterpret_cast<char*>(&structure);
auto byteVec = std::vector<unsigned char>(bytesArray, bytesArray + sizeof(TStructure));
return byteVec;
}
};
class ObjectTransformer2 : public IObjectTransformer<ObjectTransformer2> {
public:
template <typename TStructure> TStructure ToStructure(std::vector<unsigned char> bytes) {
TStructure structure{};
std::memcpy(&structure, &bytes[0], sizeof(TStructure));
return structure;
}
template <typename TStructure>
std::vector<unsigned char> ToBytes(TStructure structure) {
std::vector<unsigned char> bytes{};
bytes.resize(sizeof(TStructure));
std::memcpy(&bytes[0], &structure, sizeof(TStructure));
return bytes;
}
};
template <typename DerivedClass, typename TStructure>
void CoutStructureBytes(IObjectTransformer<DerivedClass> *objectTransformerBaseAbstractClass, TStructure structure) {
auto bytes = objectTransformerBaseAbstractClass->template ToBytes<TStructure>(structure);
for(auto byte : bytes) {
std::cout << std::to_string(byte) << ' ';
}
std::cout << std::endl;
}
int main() {
ObjectTransformer1 objectTransformer1{};
ObjectTransformer1 objectTransformer2{};
int integer = 5;
float someFloat = 9.79f;
CoutStructureBytes(&objectTransformer1, integer);
CoutStructureBytes(&objectTransformer2, someFloat);
}