从公共基 class 继承的对象的条件声明以传递对其中之一的引用

Conditional declaration of objects inherting from a common base class to pass a reference to one of them

假设我有两个 类 继承自一个共同的基础,例如

class Thing{
public:
    virtual void f()=0;
};

class Thing_variant_a: public Thing{
public:
    void f(){
        std::cout<<"I am (a)"<<std::endl;
    }
};

class Thing_variant_b: public Thing{
public:
    void f(){
        std::cout<<"I am (b)"<<std::endl;
    }
};

还有一个函数将对 Thing 对象的引用作为参数。

void function(Thing& t){
    t.f();
}

根据条件,我想用 thing_athing_b 调用 function(并可能在某些时候扩展它,添加另一种可能性 thing_c

我知道我可以使用指针来做到这一点

Thing *t = nullptr;
if(condition_a){
    t = new Thing_variant_a();
} else if(condition_b){
    t = new Thing_variant_b();
}

function(*t);

不过,我想知道有没有更好的办法,那就是

如果不是以上所有都可行,可以任意组合吗?

这是一种不使用堆或指针的方法:

Thing_variant_a thingA;
Thing_variant_b thingB;

if(condition_a){
    function(thingA);
} else if(condition_b){
    function(thingB);
}

如果需要,可以通过三元运算符将其减少为单个调用:

Thing_variant_a thingA;
Thing_variant_b thingB;
function(condition_a ? static_cast<Thing &>(thingA) : static_cast<Thing &>(thingB));

就引用而言,C++ 中的引用必须始终为非 NULL——因此如果您尝试取消引用 NULL 指针(例如,在 t==NULL 时调用 function(*t))您已经调用了未定义的行为并且注定要失败; function() 中的代码无法拯救您。因此,如果您的指针有任何变化为 NULL,则必须在 取消引用之前检查

我会尽量回答你的每一个问题

does not allocate heap memory

不幸的是,c++ 只支持使用指针的多态性。我猜你在这里面临的问题是内存碎片(这意味着你的指针在堆中无处不在)。处理该问题的最佳方法是使用内存池分配内存。

您可以使用 std::variant,但您仍需要测试变体中当前可用的类型。

does not require me to take care of deleting t at some point (probably smart pointers, but I don't know much about those)

您可以使用 std::unique_ptr,当没有人持有该指针时,它基本上会调用析构函数。

ensures I always pass a valid Thing reference to function (there might be more conditionals in a complicated structure than in this minimal example) I could do if(t){ function(*t);}else{/handle error/}), but it seems like there should be a more elegant solution.

如果您使用指针,您可以像现在一样检查 nullptr。我不确定你所说的有效引用是什么意思,因为引用总是指向某物并且不能为空。

这听起来很像 XY 问题。您的问题可能有完全不同的解决方案。

C++ 是一种静态类型的语言;这意味着给定代码路径中使用的类型在编译时是固定的。动态类型(在 运行 时间已知的类型)通常通过堆或一次性分配,然后在 运行 时间选择。

正如您所注意到的那样,您的情况不太可能..

例如,您可以只有两个不同的代码路径:

if (condition_a) {
    Thing_variant_a a;
    function(a);
} else if (condition_b) {
    Thing_variant_a b;
    function(b);
}

预分配类型:

Thing_variant_a a;
Thing_variant_a b;

if (condition_a) {
    function(a);
} else if (condition_b) {
    function(b);
}

或使用模板:

template<typename T>
void do_something() {
    T t;
    function(t);
}

// somewhere else in the code ...
do_something<Thing_variant_a>();

// or ...
do_something<Thing_variant_b>();

这里有一个使用动态内存的方法 unique_ptr:

std::unique_ptr<Thing> t;
if (condition_a) {
    t = std::make_unique<Thing_variant_a>();
} else if (condition_b) {
    t = std::make_unique<Thing_variant_b>();
}

function(*t);

// t is delete'd automatically at end of scope...

顺便说一句,像 int f(){...} 这样的函数应该 return 一些 int 值。