简体   繁体   中英

C++: Field has incomplete type

I am trying to implement the strategy design pattern as an exercise. My classes are pretty simple:

1) Fly.cpp

class Fly
{
    public:
        Fly();
        bool fly();
};

class CanFly : public Fly
{
    public:
        bool fly()
        {
            return true;
        }
};

class CantFly : public Fly
{
    public:
        bool fly()
        {
            return false;
        }
};

2) Animal.cpp

class Fly;

class Animal
{
    Fly myFly;

public:
    Animal(Fly f);
    void setFly(Fly f);
    Fly getFly();
};

Animal::Animal(Fly f)
{
    myFly = f;
}

void Animal::setFly(Fly f)
{
    myFly = f;
}

Fly Animal::getFly()
{
    return myFly;
}

3) Dog.cpp

#include <iostream>
using namespace std;

class Animal;

class Dog : public Animal
{
    public:
        Dog(Fly f);
};

Dog::Dog(Fly f)
{
    setFly(f);
    cout << "Dog : " << getFly().fly() << endl;
}

4) Bird.cpp

#include <iostream>
using namespace std;

class Animal;

class Bird : public Animal
{
    public:
        Bird(Fly f);
};

Bird::Bird(Fly f)
{
    setFly(f);
    cout << "Bird : " << getFly().fly() << endl;
}

5) AnimalTest.cpp

#include <iostream>
using namespace std;

class Dog;
class Bird;
class CanFly;
class CantFly;

int main()
{
    Fly f1 = new CanFly();
    Fly f2 = new CantFly();

    Bird b(f1);
    Dog d(f2);

    return 0;
}

The error which I get upon building the code is :

Animal.cpp:5:6: error: field 'myFly' has incomplete type 'Fly'
  Fly myFly;
      ^

Can anyone help me why?

Thanks

Incomplete type error means that compiler doesn't see definition of the class, only declaration. If you create an object or if you pass an object by value then you need to provide a definition of the class to the compiler. You do create objects and pass them around by values hence you need to include definition of relevant classes you pass into cpp files.

But that is not what you really want to do. Your intention is to employ polymorphism so you need to pass objects by reference or by pointer instead.

Your Animal class should be:

class Animal
{
    Fly &myFly;

public:
    Animal(Fly &f);
    void setFly(Fly &f);
    Fly const &getFly();
};

That way you can pass any of Fly, CanFly, or CantFly objects into Animal object.

You also need to reorganise your code. You need to separate class definitions into header files. For example:

//Animal.h
class Fly; <=== Declaration. OK here.
class Animal
{
    Fly &myFly;

public:
    Animal(Fly &f);
    void setFly(Fly &f);
    Fly const &getFly();
};

Then you need to include headers into cpp. Example:

#include "Animal.h"
class Dog : public Animal <=== Compiler needs definition of Animal here
{
    public:
        Dog(Fly f);
};

Note the difference between following definitions:

Fly Animal::getFly()
{
    return myFly;
}

Returns a copy of object stored in myFly.

Fly const &Animal::getFly()
{
    return myFly;
}

Returns a constant reference to an object myFly

Also, perhaps, you do not need Fly, CanFly, CantFly classes at all. Classes Bird, Dog already "know" if they can or cannot fly. Sure, you are doing an exercise but still Fly, CanFly, etc seem to be redundant and artificial here.

In order to use a class , its definition is required. A statement like

class Fly;

is not a definition, but merely a declaration . A class that has been declared cannot be used, but you can define pointers and references to such a class.

So, to get your code working, you should split the code into header files (.hpp) containing the class definitions and source files (.cpp) containing the (non-inline) definitions of any class members declared in the headers.

Moreover, you seem to want to use polymorphism, but forgot to declare the member bool Fly::fly() to be virtual . I think what you want is

// file Fly.hpp
struct Fly
{
  virtual bool fly() const = 0;
};

struct CanFly : Fly
{
  bool fly()
  { return true; }
};

struct CantFly : Fly
{
  bool fly()
  { return false; }
};

and then

// file Animal.hpp
struct Fly;                  // forward declaration
struct Animal
{
  const Fly*const myFly;      // use pointer to forwardly declared class
                              // const data member is public (serves as getter)
  bool fly() const;
protected:
  Animal(Fly const&f);
  // no setter: an Animal cannot change its flying behaviour
};

and

// file Animal.cpp
#include "Fly.hpp"
#include "Animal.hpp"

Animal::Animal(Fly const&f)
: myFly(&f) {}

bool Animal::fly() const
{ return myFly->fly(); }       // polymorphic call

However, I don't like this pattern. The problem is that in order to define a Bird or a Dog as derived from Animal , you need to provide a reference to an actual CanFly and CantFly , respectively, to the constructor of their base Animal . Moreover, there is nothing that qualifies an Animal other than whether it can fly or not, so why have this class Animal (in addition to Fly )?

将您的fly.cpp更改为fly.h ,在Animal.cpp您应该#include<fly.h>或者只是将myFly定义为指针Fly* myFly

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM