2016-12-12 81 views
0

例如,我试图做这样的事情:为什么不能将多态派生类嵌套在基类中?

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是一个不完整的类型,如果不需要内部类定义来定义外部类本身(因为没有内部类类型的非静态变量由外部类中的值声明)?

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

+2

一个类没有完成,直到你到达关闭'};'。 – NathanOliver

+1

在完成之前,课程并不完整。你试图做到这一点的动机是什么? –

+0

@NathanOliver:这不完全正确。你可以在'Animal'中声明'Animal'的静态成员。据我所知,内部类被视为静态。 – Matt

回答

10

类是不完整的,直到关闭大括号}的类定义。

重新“有这个”围绕一个方法,你可以做这样的事情:

struct A 
{ 
    struct B; 
}; 

struct A::B 
    : A 
{}; 

但它不是一个常见的模式。我不记得曾经见过它。

+0

谢谢,这正是我想要的(因为'struct B'可以成为'struct A'的私有成员)! – Matt

9

有没有办法解决这个问题,或者是一个更好的方法来做我想做的事情?

请勿使用嵌套类。只需将派生类从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(); } 
} 
+0

我希望这些课程是私密的。还有,听说过工厂模式?没有理由基类不能成为其有限衍生类集的工厂。 – Matt

+0

当你说私密,你的意思是隐藏的用户? –

+0

嗯,我希望他们能够有效地隐藏,而不必做任何古怪的事情。 – Matt

2

一种可能的解决方案是将狮子,老虎,猪的定义在功能范围:

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

+0

我认为,但其他任何派生类功能都无法从基类访问。而且你无法为同一个班级制作多种工厂方法。 – Matt

-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()函数,每次添加一种新的时间。

+0

如果那是我想要做的,我会做到这一点。 – Matt

相关问题