实现晚期多态性的最佳方法(Best way to achieve late

编程入门 行业动态 更新时间:2024-10-08 22:54:38
实现晚期多态性的最佳方法(Best way to achieve late-stage polymorphism)

我有几个不同的模板纯抽象类。 我从这些派生出来获得一堆类,从那里,我可以使用它们来制作一堆对象。 我想将所有这些对象放入容器中。 但是,它们都是不同的类型。 我想知道如何完成这个后期多态。

说这是我现有的预先存在的代码:

#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; }

随着更多的类,它可能会在main()内部变得非常混乱。 理想情况下,我可以jut迭代容器并在每个元素上调用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和B更改的是我添加的: public Base 。 但是,我不知道如何调用每个元素print***函数。 有没有办法调用printNum()和printTwiceNum()函数,并自动识别它们?

I have several disparate templated pure abstract classes. I derive from these to get a bunch of classes, and from there, I can use those to make a bunch of objects. I would like to put all of these objects into a container. However, they are all of different types. I am wondering how to accomplish this late-stage polymorphism.

Say this is my pre-existing code that I have right now:

#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; }

With more classes, it could get pretty messy inside of main(). Ideally I could jut iterate over the container and call print() on each element. My first thought is to use a std::vector<unique_ptr<Base>>. This seems to work:

#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; }

This is cool because I didn't have to change A_example or B_example, and all I changed in A and B was that I added : public Base. However, I have no idea how to call each elements print*** function. Is there any way to call the printNum() and printTwiceNum() functions, and for them to be automatically recognized?

最满意答案

最简单的方法是只创建一个虚函数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(); }

The simplest approach is to just make a virtual function Base::print and have your derived classes implement it. But that's not always appropriate.

Another approach is to branch on dynamic_cast conversions. The premise there is that some functions are only available on some classes. But this can get hairy especially when using class templates, as you must handle all expected template parameters.

To generalize this, you can use interface classes. Let's say you have lots of different classes but only a small number of print variations. In that case, it may make sense to do this:

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 { ... };

And now, no matter how many additional classes or template expansions you have to deal with, you only need to handle these interfaces:

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

更多推荐

本文发布于:2023-07-30 15:59:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1338809.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:多态性   晚期   方法   late   achieve

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!