C++ 从基类指针转换派生类指针

jka*_*ang -1 c++ unique-ptr

以下代码: https: //godbolt.org/z/eYEdTnMqc

#include<memory>
#include<vector>
#include<string>

class Base {
  protected:
    std::string type;
};
class Derived1 : public Base{
  protected:
    bool status;
  public:
    Derived1(): status(false), type("Derived1") {}
    void setStatus(bool newStatus) {
      status = newStatus;
    }
    bool getStatus() {
      return status;
    }
};

int main() {
  std::vector<std::shared_ptr<Base>> vars;

  vars.push_back(std::make_shared<Derived1>());
  if(!vars.back()->getStatus()) {
    vars.back()->setStatus(true);
  }
}
Run Code Online (Sandbox Code Playgroud)

给我这个编译错误:

Could not execute the program
Compiler returned: 1
Compiler stderr
<source>: In constructor 'Derived1::Derived1()':
<source>:13:32: error: class 'Derived1' does not have any field named 'type'
   13 |     Derived1(): status(false), type("Derived1") {}
      |                                ^~~~
<source>: In function 'int main()':
<source>:26:20: error: 'using element_type = class Base' {aka 'class Base'} has no member named 'getStatus'
   26 |   if(!vars.back()->getStatus()) {
      |                    ^~~~~~~~~
<source>:27:18: error: 'using element_type = class Base' {aka 'class Base'} has no member named 'setStatus'
   27 |     vars.back()->setStatus(true);
      |                  ^~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

我的基类有其他没有 getStatus() 和 setStatus() 方法的派生类,因此我不想在基类中将它们设为虚拟。

EDIT1:我编辑了代码并编译错误,以清除我的愚蠢错误,同时保持这个问题的主旨和解决方案完好无损。基本上我需要使用 std::shared_ptr 并在访问向量内的项目时使用 std::static_pointer_cast 。谢谢@雷米

编辑2:正如@remy 下面指出的那样, static_cast/dynamic_cast 到原始指针很好,因为我不打算共享所有权。所以我应该恢复到 std::unique_ptr 并使用dynamic_cast。所以解决方案是下面的代码:

https://godbolt.org/z/4Yz94z7bb

#include<memory>
#include<vector>
#include<string>

class Base {
  protected:
    std::string type;
};
class Derived1 : public Base{
  protected:
    bool status;
  public:
    Derived1(): status(false) {}
    void setStatus(bool newStatus) {
      status = newStatus;
    }
    bool getStatus() {
      return status;
    }
};

int main() {
  std::vector<std::unique_ptr<Base>> vars;

  vars.push_back(std::make_unique<Derived1>());
  static_cast<Derived1*>(vars.back().get())->setStatus(true);
}
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 6

在您显示的代码中,Derived1实际上并不派生自Base,因此您无法将Derived1*指针分配给Base*指针,因此无法将 astd::unique_ptr<Derived1>移至std::unique_ptr<Base>

改变这个:

class Derived1 {
Run Code Online (Sandbox Code Playgroud)

对此:

class Derived1 : public Base {
Run Code Online (Sandbox Code Playgroud)

然后,为了更好地衡量,您应该标记Derived1::getStatus()override

bool getStatus() override {
    return status;
}
Run Code Online (Sandbox Code Playgroud)

Base现在,话虽这么说,由于您在 中存储指针vector,您的代码仍然无法编译,因为setStatus()中没有定义方法Base,因此此语句无效:

vars.back()->setStatus(true);
Run Code Online (Sandbox Code Playgroud)

vars.back()将返回对对象的引用std::unique_ptr<Base>,然后调用operator->该对象将返回一个Base*指针,而不是Derived1*指针。因此,您需要将Base*指针强制转换回Derived1*才能访问该Derived1::setStatus()方法:

static_cast<Derived1*>(vars.back().get())->setStatus(true);
Run Code Online (Sandbox Code Playgroud)

您应该添加一个虚拟setStatus()方法来Base覆盖Derived1。那么你就不再需要演员了:

class Base {
  public:
    virtual bool getStatus() {
      return false;
    }
    virtual void setStatus(bool newStatus) {
    }
};

class Derived1 : public Base {
  protected:
    bool status;
  public:
    Derived1(): status(false) {}

    bool getStatus() override {
      return status;
    }

    void setStatus(bool newStatus) override {
      status = newStatus;
    }
};
Run Code Online (Sandbox Code Playgroud)