C ++保护的抽象类构造函数

时间:2015-08-23 16:04:09

标签: c++ constructor

我试图弄清楚抽象基类的公共构造函数和受保护构造函数之间的区别。 假设我有两个类:

抽象基类:怪物

class Monster
{
public: // or protected?? what is the techincal difference?
    Monster(string name)
    {
        _name = name;
    }
public:
    virtual void attack() = 0;

    const string getName() const
    {
        return _name;
    }

private:
    string _name;

};

具体儿童类:蜘蛛

class Spider : public Monster
{
public:
    Spider(string name) : Monster(name)
    {

    }

    void attack() override
    {
        cout << getName() << ":(Spider) is attacking!" << endl;
    }
};

现在,如果我尝试创建一个Monster实例:

int main()
{
    Monster monster1 { "Abstract Monster Not Allowed" }; // Error
}

错误: 不允许抽象类类型“怪物”的对象: Monster :: Attack是一个纯虚函数。

这完全有道理,但是“公共构造函数”是抽象类中“受保护的构造函数”的别名吗? 在哪种情况下,我可以使用受保护的构造函数来获取abtract类?

提前致谢。

4 个答案:

答案 0 :(得分:0)

当使用继承和抽象基类时,如果你的基类有一个纯虚函数virtual void doSomething() = 0;,这意味着从这个基类继承的每个类都必须实现这个函数,这个类也不能实例化,因为它将是抽象的。

与公共,受保护和&amp;的构造函数一起工作时私有成员访问这将限制类对外部调用者的行为方式。如果构造函数是public,那么可以调用该构造函数,并且只要该类不是抽象的,就可以创建该对象的实例。当构造函数受到保护时;你不能从类外部调用构造函数,但是从它继承的任何类都可以调用受保护的构造函数,除非使用了友元修饰符。

这就是抽象的意思。抽象的基类不能是对象,而是包含所有派生类之间通用的所有信息的封装概念或想法。它是可以实例化的对象的子对象。

如果您使用的是纯虚方法,则此基本类无法实例化,但是如果您只使用虚方法而不是纯虚方法,则可以实例化它!但是要小心基类中的虚方法并在构造函数中调用它们,它们可能很危险。

我将展示一个简单的抽象基类样本,包括public&amp;受保护的建设者。第一个案例将与公共建构者合作。

class Animal {
public: 
    enum AnimalType {
        AMPHIBIAN,
        BIRD,
        FISH,
        MAMMAL,
        REPTILE,
     }; // AnimalType

protected:
    AnimalType m_type;
    int m_age;
    float m_weight;

    std::string m_strVoice;

public:
    Animal( AnimalType type, int age, float weight ) :
        m_type( type ), m_age( age ), m_weight( weight )
    {}

    virtual ~Animal() {}  // Virtual Due To Inheritance

    AnimalType getType() const { return m_type; }

    void setAge( int age ) { m_age = age; }
    int  getAge() const { return m_age; }

    void setWeight( float weight ) { m_weight = weight; }
    float getWeight() const { return m_weight; }

    virtual std::string speak() = 0; // Purely Virtual All Derived Class Must Implement This
    // Abstract Class Can Not Be Instantiated

}; // Animal

class Dog : public Animal {
public:
    Dog( int age, float weight ) : Animal( AnimalType::MAMMAL, age, weight ) {}

    virtual ~Dog() {}

    std::string speak() { return std::string( "rough" ); }

}; // Dog

使用此结构,您只能在源代码中创建狗对象!

现在使用上面的相同示例展示受保护的构造函数!

class Animal {
public: 
    enum AnimalType {
        AMPHIBIAN,
        BIRD,
        FISH,
        MAMMAL,
        REPTILE,
     }; // AnimalType

protected:
    AnimalType m_type;
    int m_age;
    float m_weight;

    std::string m_strVoice;

public:
    virtual ~Animal() {}  // Virtual Due To Inheritance

    AnimalType getType() const { return m_type; }

    void setAge( int age ) { m_age = age; }
    int  getAge() const { return m_age; }

    void setWeight( float weight ) { m_weight = weight; }
    float getWeight() const { return m_weight; }

    virtual std::string speak() = 0; // Purely Virtual All Derived Class Must Implement This
    // Abstract Class Can Not Instantiate

protected:
    Animal( AnimalType type, int age, float weight ) :
        m_type( type ), m_age( age ), m_weight( weight ) {}
    // Constructor Is Protected - Doesn't Necessarily Make It Abstract
    // But Prevents Outside Code From Accessing This Constructor Only
    // Allowing Either Derived Classes Or Friends To Access This Constructor 

}; // Animal

class Mammal : public Animal {
public:
    virtual std:string speak() = 0;
protected:
    Mammal( int age, float weight ) : Animal( AnimalType::MAMMAL, age, weight ) {}     

}; // Mammal

class Dog : public Mammal {
public:
    Dog( int age, float weight ) : Mammal( age, weight ) {}

    virtual ~Dog() {}

    std::string speak() { return std::string( "rough" ); }

}; // Dog

在第二种情况下; Animal&amp;哺乳动物不能被构建为某个物体,但狗可以。这是由于受保护的构造函数。这里有动物和动物哺乳动物代表一个概念&amp;不是一个对象,但狗!我希望这可以帮助你!

答案 1 :(得分:0)

将硬币视为抽象基类。您不想直接实例化硬币对象,但是您需要构建具有不同属性的衍生类型的硬币,例如原产国,面值,然后相应地设置属性,例如它们的大小,重量和材料的。我们不希望在一些容器中放置一堆硬币基类,因为没有足够的信息来描述该硬币对象。因此,这个硬币对象是抽象的或是一个概念。然而,这个硬币基类的派生对象,例如American Silver Dollar或A German Franc等,是可以实例化的真实对象,因为它们是真实对象,并且在构造它们时已经知道关于它们的足够信息。

由于其性质以及由于类封装如何工作,即使基类不是抽象意味着不需要纯虚函数,那么硬币基类的构造函数应该受到保护!即使你确实需要在这个硬币类中使用纯虚方法,但保持构造函数受到保护仍然是一种好习惯。当他们查看您的类接口并且他们看到受保护的构造函数时,这使得源更易读。他们知道这个类不能直接实例化。

现在让我们说另一个班级有一个“硬币”类的关系,如银行班或薄荷班,薄荷类创造硬币&amp;银行类持有硬币,这些类可能具有受保护硬币构造函数的朋友访问修饰符,以便他们可以在任何可用信息之前创建这些硬币的实例并将它们存储到容器中以便稍后处理。可以将其视为预批处理操作,使用此布局,硬币基类可用作模板(不是c ++编程模板)。

答案 2 :(得分:0)

抽象类中的protected构造函数只能在构造派生类的实例的过程中调用。

但是,main()中的错误消息与受保护的构造函数无关。这是因为一个抽象类(至少有一个声明为纯虚函数的函数,正如你使用virtual void attack() = 0所做的那样)无法实例化,无论它具有什么构造函数,而且无论可访问性如何(protected,{这些构造函数的{1}}或public

派生类也不能实例化,除非它覆盖它继承的所有纯虚函数。如果它覆盖了所有继承的纯虚函数(并且没有将其自己的任何函数声明为纯虚函数),则可以对其进行实例化。

答案 3 :(得分:-1)

在C ++中,可以从任何地方访问公共类成员,但只能从派生类访问受保护的成员。私有成员只能从类本身访问,因此任何派生类都无法访问它们。

以下是有关protected constructors的更多信息。