You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中如何不使用new、不单独声明元素创建std::initializer_list<base*>并避免切片

嘿,这两个问题本质上是同一个场景的不同问法,核心都是要避免对象切片、不用动态分配(new)、不给每个派生类对象单独起名,同时保证被指向的对象拥有静态存储期。咱们一步步来看解决方案:

核心思路

要满足所有要求,关键是利用C++的static关键字来创建匿名的静态存储期派生类对象,然后直接取它们的地址放入std::initializer_list<base*>中——这样既不用单独声明变量,也不会让对象在表达式结束后销毁,还能通过指针避免切片。

具体实现示例

先定义基础的基类和派生类:

#include <initializer_list>
#include <iostream>
#include <string>

class base {
public:
    virtual void say_hello() const = 0;
    virtual ~base() = default;
};

class derived1 : public base {
public:
    void say_hello() const override {
        std::cout << "Hello from derived1!\n";
    }
};

class derived2 : public base {
private:
    std::string msg;
public:
    derived2(const std::string& m) : msg(m) {}
    void say_hello() const override {
        std::cout << "Hello from derived2: " << msg << "\n";
    }
};

1. 函数内创建std::initializer_list<base*>

如果只是在某个函数里使用这个列表,直接在初始化器中用static构造派生类对象并取地址就行:

void greet_all() {
    std::initializer_list<base*> objects = {
        &(static derived1{}),                  // 无参构造的静态匿名对象
        &(static derived2{"Custom message"})   // 带参构造的静态匿名对象
    };

    for (const auto* obj : objects) {
        obj->say_hello();  // 虚函数调用,不会切片,正确执行派生类逻辑
    }
}

这里的static非常关键:它让这个临时构造的对象变成静态局部变量,存储期覆盖整个程序运行期间,第一次初始化后就一直存在,不会像普通临时对象那样在表达式结束后销毁,所以我们拿到的地址永远有效。

2. 文件作用域(全局)的指针列表

如果需要在全局/文件作用域使用这个列表,同样可以用相同的方式:

// 文件作用域,全局可用
const std::initializer_list<base*> global_objects = {
    &(static derived1{}),
    &(static derived2{"Global instance"})
};

这些被指向的派生类对象都是静态存储期,程序启动时就会完成初始化(或第一次访问时,取决于编译器的静态初始化策略),完全不需要运行时动态分配内存,也不用单独给每个对象起名(比如d1、d2)。

为什么这能解决你的问题?
  • 避免对象切片:用基类指针指向派生类对象,虚函数机制会自动派发到正确的派生类实现,不会像直接存储对象那样丢失派生类信息。
  • 无动态分配:全程不用new,所有对象都是静态存储,内存在程序启动时就已分配好。
  • 无需单独声明变量:所有派生类对象都是匿名的,直接在列表中构造并取地址,不用额外定义d1、d2这类变量。

内容的提问来源于stack exchange,提问作者Vegard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:57:00