在创建派生类型之前,确保至少存在一个基础实例

时间:2017-01-16 19:54:12

标签: c++ inheritance instance

看起来很简单的东西一直是我目前的绊脚石。我有简单的继承,但我想确保在构造任何派生类型之前至少存在一个基类实例:

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 ) {
}

main.cpp - 第一个版本

int main() {

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

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

    return 0;
}

main.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<base_class>,以便它可以容纳任何类型,然后这些继承的类Parent&amp; Child可以包含与其关联的references to pointers个列表。然后由ManagerStorage类负责检查其容器中的第一个条目实际上是Parent类型而不是Child类类型。我继续将此添加到原始问题中,以便将来引用其他人。我仍然希望能够反馈我刚刚提到的上述结构。

1 个答案:

答案 0 :(得分:0)

为基类Parent提供一个静态整数对象,该对象在其构造函数中递增:

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

然后,如果instances = 0:

,则在Child类中抛出异常
class Child : public Parent{
    public:
        Child(){if(Parent::instances() == 0){throw "message"};

根据this wiki entry,在课程中使用throw&#39;构造函数是阻止对象实例化的标准方法,包括堆栈和堆分配。 static中的Parent成员对象仅用于保持实例总数的运行记录。