是否可以使用指向未实例化对象的指针作为 C++ 中的变量?

Is it possible to use a pointer to an uninstantiated object as a variable in C++?

我希望 C++ class 中的属性是来自特定 class 继承权的未实例化 class。然后,这个 class 家族的所有成员都将实现相同的方法,这意味着我可以实例化该对象,然后在情况需要时使用该方法。这里有一些代码(不能编译)证明了我的意思:


#include <iostream>

using namespace std;

class Event {
public:
    Event() = default;
    virtual void go() = 0;
};

class EventA : Event {
public:
    EventA() = default;

    void go(){
        cout << "Running event A"<< endl;
    }
};

class EventB : Event {
public:
    EventB() = default;


    void go(){
        cout << "Running event B"<< endl;
    }
};

class Situation{
private:
    Event* current_event = &EventA;   //Problematic code: EventA does not refer to a value
public:
    Situation() = default;

    void setEvent(Event* event){
        current_event = event;
    }

    void runEvent(){
        current_event.go();
    }
};

int main() {

    Situation situation;
    situation.runEvent();
    situation.setEvent(&EventB);
    situation.runEvent();

    return 0;
};

不,您不能形成指向 classes 的指针,并且您不能在没有 class 实例(对象)的情况下调用 [非静态] 成员函数。

您可能应该 std::make_unique 您要使用的类型的实例。

不要忘记给你的基类一个虚拟析构函数,因为你正在做多态性的事情。

静态替代方案是 std::variant

您似乎对 类 和变量感到困惑。 situation.runEvent(); 运行 会在哪个对象上?我想你想 publiclyEvent 派生 类 并在需要时初始化 current_event 。您无需执行 current_event = &EventB 之类的操作。 C++ 根据 current_event 动态指向的内容自动确定需要调用哪个函数。这就是我认为你想要做的:

#include <cassert>
#include <iostream>

class Event {
 public:
  virtual void go() = 0;
  virtual ~Event() = default;  // Don't forget the virtual destructor
};

class EventA : public Event {
 public:
  void go() override { std::cout << "Running event A" << std::endl; }
};

class EventB : public Event {
 public:
  void go() override { std::cout << "Running event B" << std::endl; }
};

class Situation {
 private:
  Event* current_event = nullptr;

 public:
  void setEvent(Event* event) { current_event = event; }

  void runEvent() {
    assert(current_event);
    current_event->go();
  }
};

int main() {
  Situation situation;
  EventA a;
  EventB b;
  situation.setEvent(&a);
  situation.runEvent();
  situation.setEvent(&b);
  situation.runEvent();
}

在两个地方,您似乎在做可以被描述为试图从类型中获取指针的事情:

Event* current_event = &EventA;

situation.setEvent(&EventB);

这是行不通的,在 C++ 中也不是真正具有适当意义的东西。您尝试做的事情可以通过我能想到的 3 种不同的方式实现。

方法 1:您可以使用函数指针代替 class,并将函数指针作为参数传递:

#include <iostream>

using namespace std;

void eventA_go(){
    cout << "Running event A"<< endl;
}

void eventB_go(){
    cout << "Running event B"<< endl;
}

class Situation{
private:
    using EventFunctionPtr = void (*)();
    EventFunctionPtr current_event = &eventA_go;
public:
    Situation() = default;

    void setEvent(EventFunctionPtr event){
        current_event = event;
    }

    void runEvent(){
        current_event();
    }
};

int main() {

    Situation situation;
    situation.runEvent();
    situation.setEvent(&eventB_go);
    situation.runEvent();

    return 0;
};

方法 2:您可以使此代码更通用一些,方法是在 Situation class 中允许任何类型的可调用对象,而不仅仅是函数指针:

#include <iostream>
#include <functional>

using namespace std;

void eventA_go(){
    cout << "Running event A"<< endl;
}

void eventB_go(){
    cout << "Running event B"<< endl;
}

class Situation{
private:
    std::function<void ()> current_event = eventA_go;
public:
    Situation() = default;

    template <typename F>
    void setEvent(F&& event){
        current_event = event;
    }

    void runEvent(){
        current_event();
    }
};

int main() {

    Situation situation;
    situation.runEvent();
    situation.setEvent(&eventB_go);
    situation.runEvent();

    return 0;
};

方法 3:您可以回到最初的想法,即必须实现一个基础 class 以提供 go() 方法,但在这种情况下,您实际上必须确保您调用的对象确实存在。一种可能的方法是 std::unique_ptr:

#include <iostream>
#include <memory>

using namespace std;

class Event {
public:
    Event() = default;
    virtual ~Event() = default;
    virtual void go() = 0;
};

class EventA : public Event {
public:
    EventA() = default;

    void go(){
        cout << "Running event A"<< endl;
    }
};

class EventB : public Event {
public:
    EventB() = default;

    void go(){
        cout << "Running event B"<< endl;
    }
};

class Situation{
private:
    std::unique_ptr<Event> current_event = std::make_unique<EventA>();
public:
    Situation() = default;

    void setEvent(std::unique_ptr<Event>&& event){
        current_event = std::move(event);
    }

    void runEvent(){
        current_event->go();
    }
};

int main() {

    Situation situation;
    situation.runEvent();
    situation.setEvent(std::make_unique<EventB>());
    situation.runEvent();

    return 0;
};

注意,在这种情况下,抽象class的析构函数必须是virtual,继承必须是public.