我有几个不同的模板纯抽象类。我从这些派生出来获得一堆类,从那里,我可以使用它们来制作一堆对象。我想将所有这些对象放入容器中。但是,它们都是不同的类型。我想知道如何完成这个后期多态性。
说这是我现有的预先存在的代码:
public static class AssemblyHelper
{
//--------------------------------------------------------------------------------
/// <summary>
/// Redirection hack because Azure functions don't support it.
/// How to use:
/// If you get an error that a certain version of a dll can't be found:
/// 1) deploy that particular dll in any project subfolder
/// 2) In your azure function static constructor, Call
/// AssemblyHelper.IncludeSupplementalDllsWhenBinding()
///
/// This will hook the binding calls and look for a matching dll anywhere
/// in the $HOME folder tree.
/// </summary>
//--------------------------------------------------------------------------------
public static void IncludeSupplementalDllsWhenBinding()
{
var searching = false;
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
// This prevents a stack overflow
if(searching) return null;
var requestedAssembly = new AssemblyName(args.Name);
searching = true;
Assembly foundAssembly = null;
try
{
foundAssembly = Assembly.Load(requestedAssembly);
}
catch(Exception e)
{
Debug.WriteLine($"Could not load assembly: {args.Name} because {e.Message}");
}
searching = false;
if(foundAssembly == null)
{
var home = Environment.GetEnvironmentVariable("HOME") ?? ".";
var possibleFiles = Directory.GetFiles(home, requestedAssembly.Name + ".dll", SearchOption.AllDirectories);
foreach (var file in possibleFiles)
{
var possibleAssembly = AssemblyName.GetAssemblyName(file);
if (possibleAssembly.Version == requestedAssembly.Version)
{
foundAssembly = Assembly.Load(possibleAssembly);
break;
}
}
}
return foundAssembly;
};
}
}
有了更多的课程,#include <iostream>
template<typename T>
class A{
public:
A() : m_num(1.0) {};
virtual ~A() {};
virtual void printNum() const = 0;
protected:
T m_num;
};
template<typename T>
class B{
public:
B() : m_num(2.0) {};
virtual ~B() {};
virtual void printTwiceNum() const = 0;
protected:
T m_num;
};
class A_example : public A<int>
{
public:
A_example() : A<int>() {};
void printNum() const { std::cout << m_num << "\n"; };
};
class B_example : public B<int>
{
public:
B_example() : B<int>() {};
void printTwiceNum() const { std::cout << 2*m_num << "\n"; };
};
int main(){
A_example first;
B_example second;
first.printNum();
second.printTwiceNum();
return 0;
}
内部可能会变得非常混乱。理想情况下,我可以jut遍历容器并在每个元素上调用main()
。我的第一个想法是使用print()
。这似乎有效:
std::vector<unique_ptr<Base>>
这很酷,因为我不必更改#include <iostream>
#include <vector> // new include
#include <memory> // new include
#include <utility> // new include
// new Base class here
class Base{
public:
virtual ~Base(){};
};
template<typename T>
class A : public Base{ // new inheritance here
public:
A() : m_num(1.0) {};
virtual ~A() {};
virtual void printNum() const = 0;
protected:
T m_num;
};
template<typename T>
class B : public Base{ // new inheritance here as well
public:
B() : m_num(2.0) {};
virtual ~B() {};
virtual void printTwiceNum() const = 0;
protected:
T m_num;
};
class A_example : public A<int>
{
public:
A_example() : A<int>() {};
void printNum() const { std::cout << m_num << "\n"; };
};
class B_example : public B<int>
{
public:
B_example() : B<int>() {};
void printTwiceNum() const { std::cout << 2*m_num << "\n"; };
};
int main(){
std::vector<std::unique_ptr<Base>> v;
v.emplace_back( new A_example() );
v.emplace_back( new B_example() );
//v[0]->printNum(); // nope
//v[1]->printTwiceNum(); // nope
return 0;
}
或A_example
,而我在B_example
和A
中更改的内容是我添加的{{1} }。但是,我不知道如何调用每个元素B
函数。有没有办法调用: public Base
和print***
函数,并自动识别它们?
答案 0 :(得分:4)
最简单的方法是创建一个虚函数Base::print
并让派生类实现它。但这并不总是合适的。
另一种方法是分支dynamic_cast
次转化。前提是某些功能仅适用于某些类。但是,这可能会变得毛茸茸,特别是在使用类模板时,因为您必须处理所有预期的模板参数。
要概括这一点,您可以使用接口类。我们假设您有很多不同的类,但只有少量的打印版本。在这种情况下,这样做可能有意义:
class PrintNumInterface {
public:
virtual void printNum() const = 0;
};
class PrintTwiceNumInterface {
public:
virtual void printTwiceNum() const = 0;
};
template<typename T> class A : public Base, public PrintNumInterface { ... };
template<typename T> class B : public Base, public PrintTwiceNumInterface { ... };
现在,无论您需要处理多少额外的类或模板扩展,您只需要处理这些接口:
for (auto& p : v)
{
if (PrintNumInterface* iface = dynamic_cast<PrintNumInterface*>(p.get())
iface->printNum();
else if (PrintTwiceNumInterface* iface = dynamic_cast<PrintTwiceNumInterface*>(p.get())
iface->printTwiceNum();
}