多态局部变量的近似值

Approximation of a polymorphic local variable

本文关键字:近似值 局部变量 多态      更新时间:2023-10-16

我想让局部变量的运行时类型取决于某些条件。假设我们有这种情况:

#include <iostream>
class Base{ 
public:
    virtual void foo()=0; 
};
class Derived1 : public Base {
    virtual void foo(){
        std::cout << "D1" << std::endl;
    }
};
class Derived2 : public Base {
    virtual void foo(){
        std::cout << "D2" << std::endl;
    }
};

在类Java语言中,对象总是通过"引用"处理,解决方案很简单(伪代码(:

Base x = condition ? Derived1() : Derived2();

C++解决方案显然会涉及指针(至少在幕后(,因为没有其他方法可以将两种不同的类型放在同一个变量(必须有一个类型(下。它不能简单地Base因为Base对象不能被构造(它有一个纯虚函数(。

最简单的方法是使用原始指针:

Base* x = condition ? static_cast<Base*>(new Derived1()) : static_cast<Base*>(new Derived2());

(需要强制转换才能使三元运算符的两个分支具有相同的类型(

手动指针处理容易出错且老派,这种情况需要unique_ptr

std::unique_ptr<Base> x{condition ? static_cast<Base*>(new Derived1()) : static_cast<Base*>(new Derived2())};

啊。。。不完全是我所说的优雅。它使用显式新建和强制转换。我希望使用类似std::make_unique的东西来隐藏new但这似乎是不可能的。

这只是你得出结论"C++就是这样,如果你需要优雅,使用其他语言(也许在其他方面做出权衡("的情况之一?

还是这整个想法完全不C++?我在这里的心态是错误的,试图将不同语言的想法强加给C++吗?

这只是你得出结论"C++就是这样,如果你需要优雅,使用其他语言(也许在其他方面做出权衡("的情况之一?

还是这整个想法完全不C++?我在这里的心态是错误的,试图将不同语言的想法强加给C++吗?

这实际上取决于您将使用x做什么。

变种

C++解决方案显然会涉及指针(至少在幕后(,因为没有其他方法可以将两种不同的类型放在同一个变量下(必须有一个类型(。

您也可以使用 boost::variant(或boost::any ,但在这种情况下boost::variant可能会更好(。例如,假设Derived1是默认可构造的:

boost::variant<Derived1, Derived2> x;
if (!condition) x = Derived2();

即使Derived1Derived2不共享基类,这也将起作用。然后,您可以使用访客模式对x进行操作。例如,给定:

struct Derived1 {
    void foo1(){
        std::cout << "D1" << std::endl;
    }
};
struct Derived2 {
    void foo2(){
        std::cout << "D2" << std::endl;
    }
};

然后,您可以将访问者定义为:

class some_visitor : public boost::static_visitor<void> {
public:
    void operator()(Derived1& x) const {
        x.foo1();
    }
    
    void operator()(Derived2& x) const {
        x.foo2();
    }
};

并将其用作:

boost::apply_visitor(some_visitor(), x);

现场演示

多态调用

如果您真的需要多态地使用x,那么是的,std::unique_ptr都可以。只需将您的多态函数称为x->foo()

std::unique_ptr<Base> x = condition ? std::unique_ptr<Base>(new Derived1()) : std::unique_ptr<Base>(new Derived2());

现场演示

概念/模板

如果你只需要调用一个函数,那么定义一个概念并用模板表达它可能更好:

template<class Type>
void my_func(Type& x) { x.foo(); }

您也可以在将来的C++版本中明确定义概念。

现场演示

一种"激进"的可能性是创建一种新的make_unique,它将创建正确的类型返回值

template<typename TReal, typename TOutside, typename... Args>
auto make_base_unique(Args&&... args) -> std::unique_ptr<TOutside>
{
    return std::unique_ptr<TOutside>(new TReal(std::forward<Args>(args)...));
}

然后像这样使用它:

auto x = (condition ? make_base_unique<Derived1,Base>() : make_base_unique<Derived2,Base>());