Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何根据构造函数参数初始化具有超类类型的成员变量?_C++_Pointers_Inheritance_Member - Fatal编程技术网

C++ 如何根据构造函数参数初始化具有超类类型的成员变量?

C++ 如何根据构造函数参数初始化具有超类类型的成员变量?,c++,pointers,inheritance,member,C++,Pointers,Inheritance,Member,经过几个小时的搜索,我终于来到了这里。我有一个容器类,其成员变量是指向基类的指针。这应该引用Spec1或另一个继承的Base类,我在这里省略了它们。类型应由构造函数中的参数确定,例如字符串、枚举、int等 我读了很多关于动态内存分配的书,以及为什么应该尽可能避免动态内存分配。在这里可以避免吗?构造器之后没有任何普通对象被销毁吗?还是设计理念完全错误?我来自爪哇:提前谢谢 class Base{ public: virtual ~Base(){}; // required? v

经过几个小时的搜索,我终于来到了这里。我有一个容器类,其成员变量是指向基类的指针。这应该引用Spec1或另一个继承的Base类,我在这里省略了它们。类型应由构造函数中的参数确定,例如字符串、枚举、int等

我读了很多关于动态内存分配的书,以及为什么应该尽可能避免动态内存分配。在这里可以避免吗?构造器之后没有任何普通对象被销毁吗?还是设计理念完全错误?我来自爪哇:提前谢谢

class Base{
  public:
    virtual ~Base(){}; // required?
    virtual void doSomething() = 0;
};

class Spec1 : public Base {
     public:
       Spec1(){};
       Spec1(int i){
         // whatever
       }
       void doSomething(){
          std::printf("hello world");
       }
};

class Container{
   public:
     Container(String type_message){
      if (type_message.compare("We need Spec1")){
          m_type = new Spec1(1);
      } // add more ifs for other types (Spec2, Spec3 etc.)
     }
     void doSomethingWithSpec(){
        m_type->doSomething();
     }
   private:
      Base* m_type;
 };

int main (int argc, char **argv){
    Container a ("We need Spec1");
    a.doSomething();
}

构造函数与任何其他函数一样工作。本地变量在堆栈中分配,当函数完成时,超出范围,而动态内存分配在堆栈中完成,需要在函数完成之前明确地释放C++而不是java。 但是在你的情况下

m_type = new Spec1(1);
新的Spec11是在堆中动态分配的,在构造函数代码完成时不会被销毁。引用存储在类的成员变量中。因此,只要类容器的实例在作用域中,就可以引用分配给Spec11的内存

比较,只考虑其他方案。

Container(String type_message){
      Base* m_type;
      if (type_message.compare("We need Spec1")){
          m_type = new Spec1(1);
      } // add more ifs for other types (Spec2, Spec3 etc.)
     }
在这里,一旦构造函数完成,m_type将超出范围,但新的Spec11仍将存在于堆中,因为内存泄漏。

要求容器知道每一个可能的基类派生类听起来并不是一个好的设计。这就是工厂功能的用途

让容器将该对象存储为std::unique_ptr,以避免内存泄漏和手动内存管理

struct Base {
    virtual ~Base() = default;
    virtual void doSomething() = 0;
};

struct Spec1 : Base {
    void doSomething() override {
        std::printf("%s\n", __PRETTY_FUNCTION__);
    }
};

// Factory function.
std::unique_ptr<Base> createBase(std::string const& type) {
    if(type == "Spec1")
        return std::unique_ptr<Base>(new Spec1);
    throw std::runtime_error("Unknown type " + type);
}

class Container {
    std::unique_ptr<Base> m_type;
public:
    Container(std::string const& type)
        : m_type(createBase(type))
    {}

    void doSomething(){
        m_type->doSomething();
    }
};

int main() {
    Container a ("Spec1");
    a.doSomething();
}

建议在您的案例中使用std::unique_ptr和std::make_unique,而不是原始指针和new。虽然容器缺少调用delete m_type的析构函数,但您的设计总体上是不错的;并且还应该禁用默认的复制构造函数和复制赋值运算符,因为不应该按原样复制m_类型。是的,~Base需要是虚拟的,所以删除m_type;将正常工作,调用您选择实例化的任何派生类型的析构函数。如果程序被ctrl-c ubuntu终端中止,是否调用析构函数?或者我必须手动调用析构函数吗?关于动态分配是“尽可能避免”,这是正确的,但是如果你想要C++中的多态性,那么你必须使用指针或引用,因此,在这样的情况下,即引用不合适的情况下,您需要使用动态分配。因此,没有可能避免使用新的?这是new的典型用例吗?这里的new与Java中的new相似。通过不将基类对象声明为指针,可以避免出现新问题。基本m_型;m_type=Spec11您应该尽可能避免动态分配。是一个很好的读取器,对虚拟类不起作用:错误:无法将字段“Container::m_type”声明为抽象类型“Base”Base m_type;感谢工厂的功能,以前不知道。但实际上我想保持它的简洁,我以前在构造函数中做过其他事情,所以这些都会传递给createBase方法。@Lucker10容器和Base看起来像。