为什么多态派生类不能嵌套在基类中?

时间:2016-12-12 18:16:17

标签: c++ inheritance polymorphism inner-classes

例如,我试图做这样的事情:

class Animal {
public:
    virtual const char *says() const = 0;

    static Animal *makeLion() { return new Lion(); }
    static Animal *makeTiger() { return new Tiger(); }
    static Animal *makePig() { return new Pig(); }

private:
    class Lion : public Animal { // error: invalid use of incomplete type ‘class Animal’
    public:
        virtual const char *says() const
        {
            return "roar";
        }
    };

    class Tiger : public Animal { // error: invalid use of incomplete type ‘class Animal’
    public:
        virtual const char *says() const
        {
            return "meow";
        }
    };

    class Pig : public Animal { // error: invalid use of incomplete type ‘class Animal’
    public:
        virtual const char *says() const
        {
            return "That\'s all Folks!";
        }
    };
};

编译器抱怨Animal是一个不完整的类型。但是为什么Animal是一个不完整的类型,如果内部类定义不需要定义外部类本身(因为内部类类型的非静态变量是由外部类中的值声明的)?

有没有办法解决这个或更好的方法来做我想做的事情?

4 个答案:

答案 0 :(得分:11)

在类定义的右大括号}之前,类尚未完成。

Re“有解决方法”,你可以这样做:

struct A
{
    struct B;
};

struct A::B
    : A
{};

但它并不常见。我不记得曾见过它。

答案 1 :(得分:10)

  

有没有办法绕过这个或更好的方式去做我想做的事情?

不要使用嵌套类。只需将派生类移出Animal

单独注意,有功能

static Animal *makeLion() { return new Lion(); }
static Animal *makeTiger() { return new Tiger(); }
static Animal *makePig() { return new Pig(); }
Animal中的

是设计不佳的症状。基类应该尽可能与从它派生的类不可知。

这里建议更清洁的界面和实施:

Animal.h:

namespace AnimalsNamespace
{
   // The base class
   class Animal
   {
      public:
         virtual const char *says() const = 0;
   };


   // Functions to construct objects of various sub-types of Animal.
   // Moving these out of Animal and putting them in the namespace makes
   // Animal a little bit cleaner.

   Animal* makeLion();
   Animal* makeTiger();
   Animal* makePig();
}

Animal.cpp:

namespace AnimalsNamespace
{
   class Lion : public Animal
   {
      public:
         virtual const char *says() const
         {
            return "roar";
         }
   };

   class Tiger : public Animal
   {
      public:
         virtual const char *says() const
         {
            return "meow";
         }
   };

   class Pig : public Animal
   {
      public:
         virtual const char *says() const
         {
            return "That\'s all Folks!";
         }
   };

   Animal* makeLion() { return new Lion(); }
   Animal* makeTiger() { return new Tiger(); }
   Animal* makePig() { return new Pig(); }
}

答案 2 :(得分:2)

一种可能的解决方案是将Lion,Tiger,Pig的定义放在功能范围内:

class Animal {
public:
    virtual ~Animal() = default;
    virtual const char *says() const = 0;

    static std::unique_ptr<Animal> makeLion()
    {
        class Lion : public Animal
        {
        public:
            virtual const char *says() const override
            {
                return "roar";
            }
        };
        return std::make_unique<Lion>();
    }
    static std::unique_ptr<Animal> makeTiger() {
        class Tiger : public Animal
        {
        public:
            virtual const char *says() const override
            {
                return "meow";
            }
        };
        return std::make_unique<Tiger>();
    }
    static std::unique_ptr<Animal> makePig() {
        class Pig : public Animal
        {
        public:
            virtual const char *says() const override
            {
                return "That\'s all Folks!";
            }
        };
        return std::make_unique<Pig>();
    }
};

int main() {    
    std::cout << Animal::makeLion()->says() << std::endl;
}

Demo

答案 3 :(得分:-1)

糟糕的设计。不应在Animal类中创建对象。考虑重新设计类:

class Animal
{
public:
    virtual const char* says() const = 0;
};

class Lion : public Animal
{
public:
    virtual const char *says() const
    {
        return "roar";
    }
};

class Tiger : public Animal
{
public:
    virtual const char *says() const
    {
        return "meow";
    }
};

class Pig : public Animal
{
public:
    virtual const char *says() const
    {
        return "That\'s all Folks!";
    }
};

然后像这样使用:

Animal* p = new Pig;
cout << p->says() << endl;

否则,每次添加新类型时都必须添加makeXXX()函数。