【问题标题】:Making sure at least one instance of a base exists before creating a derived type在创建派生类型之前确保至少存在一个基类实例
【发布时间】:2017-01-16 19:54:12
【问题描述】:

看似简单的事情一直是我当前的绊脚石。我有简单的继承,但我想确保在构造任何派生类型之前至少存在一个基类实例:

class Parent {
private:
    std::string name_;

    explicit Parent( const std::string& name );

protected:
    // Constructor that Derived Types Will Use
    Parent( const std::string& parentName, const std::string& childName, bool isChildAParent = false );

};

Child : public Parent {
public:
    Child( const std::string& parentName, const std::string& childName, bool isChildAParent = false );
};

// It is here in the 2nd or protected constructor that I'm struggling with.
Parent::Parent( const std::string& parentName, const std::string& childName, bool isChildAParent ) {

    // How To Go about to check if an instance of Parent already exists that
    // used its default constructor before using this constructor from a derived type?

}

主要的用法是这样的:

int main() {
    Child child( "parent", "child", false ); // Invalid since Parent wasn't created first

    Parent parent( "parent" );
    Child child( "parent", "child", false ); // Okay since parent exists.

    return 0;
}

编辑 - 基于Kerrek SB 的评论说明

我可能在某处需要一个静态成员

这就是我现在所做的,我得到了我所期望的行为。

.h

class Parent {
private:
    std::string myName_; // Name of this parent
    static bool isConstructed_;
    bool isParent_;
protected:
    std::string parentName_;
public:

    // This must be called first at least once before trying to create any children classes.
    // The importances of this dependence has to do with the pointer of this parent being stored
    // in a vector (outside of this class), and every child created after this will create a family that belongs to this parent.

    explicit Parent( const std::string& name ); 
    Parent( Parent &&self );
    Parent& operator=( Parent &&transfer );

    Parent( Parent const & ) = delete;
    Parent& operator=( Parent const & ) = delete;

    //*virtual*/ void print() { }


    virtual void printName() const;
    virtual void printParentName() const;

    const std::string& getName() const;
    const std::string& getParentName() const;

protected:
    // Constructor that is used when using inheritance.
    explicit Parent( const std::string& parentName, const std::string& childName, bool isChildAParent = false );
};

class Child : public Parent {
public:
    Child( const std::string& parentName, const std::string& childName, bool isChildAParent = false );
};

.cpp

bool Parent::isConstructed_ = false;

// Initial Constructor Must Be Called First At Least Once.
Parent::Parent( const std::string& parentName ) :
myName_( parentName ) { 
    isConstructed_ = true;
    isParent_ = true;
}

// Protected Constructor Used By Child Classes.
Parent::Parent( const std::string& parentName, const std::string& childName, bool isChildAParent ) {
    // First check to see if this child will be a parent itself
    if ( !isConstructed_ ) {
        std::cout << "There must be at least 1 instance of a Parent\n"
                  << "before constructing a child.\n";
    } else {
        myName_ = childName;
        parentName_ = parentName;
        isParent_ = isChildAParent;
    }
}

// Move Constructor
Parent::Parent( Parent&& self )  {
}

// Move Opeartor
Parent& Parent::operator=( Parent&& self ) {
    if ( this != &self ) {
    }
    return *this;
}

void Parent::printName() const {
    std::cout << myName_ << std::endl;
}

void Parent::printParentName() const {
    std::cout << parentName_ << std::endl;
}

const std::string& Parent::getName() const {
    return myName_;
}

const std::string& Parent::getParentName() const {
    return parentName_;
}

Child::Child( const std::string& parentName, const std::string& childName, bool isChildAParent ) :
Parent( parentName, childName, isChildAParent ) {
}

ma​​in.cpp - 第一个版本

int main() {

    Parent  p( "someParent" );
    Child   c( "someParent", "someChild" );

    // Child's Construction is successful because Parent p exists         

    return 0;
}

ma​​in.cpp - 版本 2

int main() {
    Child c( "someParent", "someChild" );

    // Still compiles and prints out the message that a parent needs to exists first
    // This can be thrown as an exception to prevent the creation
    // of a derived type without at least having a base type that already exists.

    return 0;
}

谢谢Kerrek SB

编辑 -- 在考虑了我需要的 ParentChild 类之间的关系之后,我想我得出的结论是,拥有另一个类可能会更好将是一个Abstract Base ClassParentChild 类型将彼此独立地继承。这样,我的 ManagerStorage 具有这些容器的类将接受 shared_ptr&lt;base_class&gt; 以便它可以容纳任何一种类型,然后这些继承的类 ParentChild 可以包含 references to pointers 的列表与它们相关联的那些。然后由ManagerStorage 类负责检查其容器中的第一个条目是否实际上是Parent 类型而不是Child 类型。我继续将此添加到原始问题中,以供将来参考。我仍然希望对我刚才提到的上述构造提供一些反馈。

【问题讨论】:

  • 你可能需要一个静态成员。
  • 这对我来说就像一个XY Problem,你实际上想解决什么问题?
  • 如果你改变Child的构造函数需要一个Parent的引用,你可以确定存在一个Parent
  • 只知道Parent 已创建是没有意义的。如果有实际原因,那么Child 必须有某种方式与Parent 通信。那么假设有这种方式,为什么不能检查实际状态呢?
  • 当你创建一个子类时,必须创建父类,当然,但它们都是同一个对象的一部分。您正在询问一个单独的 Parent 对象。由于这是一种非常规的继承用法,我真的认为您应该展示实际的用例,而不是寻找特定的 hack。我很高兴您的问题得到了解答,但我认为如果您描述了实际问题,您本可以得到可以进一步改进您的解决方案的答案。

标签: c++ inheritance instance


【解决方案1】:

给基类Parent一个在其构造函数中递增的静态整数对象:

class Parent{
    public:
        Parent(){instances++;}
        ~Parent(){instances--;}
        unsigned int instances(){return instances;}
    private:
        static unsigned int instances = 0;

然后,如果实例 = 0,则在 Child 类中抛出异常:

class Child : public Parent{
    public:
        Child(){if(Parent::instances() == 0){throw "message"};

根据this wiki entry,在类的构造函数中使用throw 是防止对象实例化的标准方法,无论是堆栈分配还是堆分配。 Parent 中的 static 成员对象仅用于保持实例总数的运行记录。

【讨论】:

  • 我不需要知道有多少或跟踪,我只需要知道是否首先存在至少 1 个 Parent 实例。但感谢您的尝试。
  • 这是实现您既定目标的完美方法。
  • 是的,但是只有一个静态布尔值就可以了。如果调用了 Parent 的 Public 构造函数,则该标志设置为 true。然后,如果正在调用使用 Base 类型的受保护构造函数的 Derived 类型,它将检查该静态 bool 以查看是否至少存在一个实例。
  • @FrancisCugler 这行得通,但是如果这些 Parent 对象超出范围或被删除怎么办?您需要将布尔值更改为 false;但是您如何跟踪所有实例?删除一个并不一定意味着范围内没有任何父母,因此实例变量可以帮助您跟踪。可能是一种基于布尔值的方法,但对我来说这是最常见的方法。
  • 我可能会重新考虑我的设计模式,可能会完全取消继承,只需在类中添加一个标志以指示此特定实例是父实例还是子实例以删除该依赖关系。然后让管理器类、树列表结构管理它们的关联。
猜你喜欢
  • 2014-09-29
  • 1970-01-01
  • 2013-05-03
  • 2014-04-17
  • 1970-01-01
  • 2013-01-04
  • 2023-03-19
  • 2011-11-05
  • 2021-11-19
相关资源
最近更新 更多