【问题标题】:C++: Field has incomplete typeC++:字段类型不完整
【发布时间】:2015-07-18 09:46:56
【问题描述】:

我正在尝试实施策略设计模式作为练习。我的课程非常简单:

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;
}

我在构建代码时遇到的错误是:

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

谁能帮我解释一下为什么?

谢谢

【问题讨论】:

  • 你知道什么是抽象类吗?
  • 应该不能不“不能”。阅读关键字virtual
  • fly 构造函数需要一个主体
  • ... 阅读参考资料和const 给你一些事情做:-)
  • 请阅读基本的编程介绍。

标签: c++ inheritance design-patterns


【解决方案1】:

不完整的类型错误意味着编译器看不到类的定义,只有声明。 如果创建对象或按值传递对象,则需要向编译器提供类的定义。您确实创建了对象并通过值传递它们,因此您需要包含传递到 cpp 文件中的相关类的定义。

但这并不是你真正想做的。 您的意图是使用多态性,因此您需要通过引用或指针来传递对象。

你的 Animal 类应该是:

class Animal
{
    Fly &myFly;

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

这样您就可以将任何 Fly、CanFly 或 CantFly 对象传递给 Animal 对象。

您还需要重新组织代码。您需要将类定义分成头文件。例如:

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

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

然后你需要在 cpp 中包含 headers。示例:

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

注意以下定义之间的区别:

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

返回存储在 myFly 中的对象的副本。

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

返回一个对 myFly 对象的常量引用

另外,也许你根本不需要Fly, CanFly, CantFly 类。 Bird, Dog 的班级已经“知道”他们是否可以飞行。当然,你正在做一个练习,但 Fly、CanFly 等在这里似乎是多余的和人为的。

【讨论】:

  • +1,但也许您应该解释为什么在这种情况下(多态性)它们应该通过引用或指针传递,因为情况并非总是如此。
【解决方案2】:

为了使用class,需要其定义。像

这样的声明
class Fly;

不是一个定义,而仅仅是一个声明。已声明的类不能使用,但可以定义指向该类的指针和引用。

因此,为了让您的代码正常工作,您应该将代码拆分为包含类定义的头文件 (.hpp) 和包含在头文件中声明的任何类成员的(非内联)定义的源文件 (.cpp) .

此外,您似乎想使用多态性,但忘记将成员bool Fly::fly() 声明为virtual。我想你想要的是

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

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

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

然后

// 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
};

// 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

但是,我不喜欢这种模式。问题是,为了定义从Animal 派生的BirdDog,您需要分别提供对实际CanFlyCantFly 的引用,指向它们的基类@ 的构造函数987654333@。况且Animal除了能不能飞,没有什么能比得上它,那为什么还要Animal这个类(除了Fly)?

【讨论】:

  • 我认为bool Fly 用于名为Fly 的对象也可能是一个问题
  • 如果你想让Fly 表现出多态性,你就不能按值来取它,这只会将它切片。
  • @EdHeal ?? bool Fly在哪里?
  • ... 抱歉 - 一个是大写的,另一个不是。无论如何,仅仅依靠大写的方法的一个愚蠢的名字
  • @EdHeal 依赖大写的方法的愚蠢名称 这是一种常用方法,我只是从 OP 中复制的。
【解决方案3】:

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

【讨论】:

  • 这并不能说明问题。
  • @Walter 他的文件层次结构很差。在Animal.cpp 中没有#include&lt;fly.h&gt;,编译器找不到class Fly 的定义。所以它会警告它是一个不完整的类。只需将字段定义为指针,编译器就不需要它的定义。
  • @Shindou - 可能是这样,但你的回答并不能解决问题
猜你喜欢
  • 1970-01-01
  • 2017-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-10
相关资源
最近更新 更多