C++类方法,返回向量<子类>;子类>
我尝试为课程编写的方法遇到了一些麻烦。我有班级符号和班级终端。类终端扩展了类符号,但类符号的方法之一需要返回一个向量。例如:
#ifndef SYMBOL_H
#define SYMBOL_H
#include "terminal.h"
#include <vector>
using namespace std;
class symbol {
public:
vector<terminal> first();
virtual void polymorphable();
};
#endif
定义了类终端:
#ifndef TERMINAL_H
#define TERMINAL_H
#include "symbol.h"
using namespace std;
class terminal: public symbol {
// ...
};
#endif
但是,在执行此操作时,我在构建时遇到两个错误,其中一个或另一个先出现:定义向量函数的行上的“'terminal':未声明的标识符”和“'symbol'” : 基类未定义”与终端类定义一致。
如何解决“a 需要 b”、“b 需要 a”问题?
I'm having a bit of trouble with a method I'm trying to write for a class. I have class symbol and class terminal. class terminal extends class symbol, but one of the methods of class symbol needs to return a vector. E.g.:
#ifndef SYMBOL_H
#define SYMBOL_H
#include "terminal.h"
#include <vector>
using namespace std;
class symbol {
public:
vector<terminal> first();
virtual void polymorphable();
};
#endif
With class terminal defined:
#ifndef TERMINAL_H
#define TERMINAL_H
#include "symbol.h"
using namespace std;
class terminal: public symbol {
// ...
};
#endif
However, when doing this, I get two errors when building, with one or the other coming first: "'terminal' : undeclared identifier" on the line that defines the vector function, and "'symbol' : base class undefined" on the line with the terminal class definition.
How do I solve this 'a requires b', 'b requires a' issue?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
使用转发声明避免循环依赖。
通过 推测此方法根据 C++ 标准未定义。
@Ben Voight 指出:
C++03 标准第 17.6.4.8 节说:
无论< code>std::vectorf(); 是
std::vector
的一个实例化,正在讨论此处如果那里的答案证明了这一点。那么这个答案没有用,我将删除它,否则它仍然有效。Avoid circular dependencies by using Forward Declarations.
There is a speculation of this approach being Undefined as per C++ standard.
@Ben Voight points out:
C++03 standard Section 17.6.4.8 says:
Whether
std::vector<X> f();
isstd::vector<X>
an instantiation, is being discussed here. If the answer there proves it is then this answer holds no good and I will delete the same, or else this stays valid.编辑:标准可能不允许以下内容(请参阅评论)。在这种情况下,您根本无法拥有适当的循环依赖项:如果
A
的大小取决于类型B
的成员的大小,但的大小B
取决于类型A
成员的大小,那么这样的定义根本没有意义。不过,我并不完全确定这是否适用于您的情况,因为您只声明了一个返回类型不完整的函数,这是允许的。请参阅詹姆斯提出的问题;希望我们能在那里得到明确的答案。
只需前向声明
terminal
:您可以前向声明任何只需为不完整类型的内容。不完整类型可用于形成指针、引用、函数签名。仅当使用该类型的变量时才需要知道完整类型。
Edit: The following may not be allowed by the standard (see the comments). In that case, you simply cannot have a proper circular dependency: If the size of
A
depends on the size of a member of typeB
, but the size ofB
depends on the size of a member of typeA
, then such a definition simply doesn't make sense.I'm not entirely certain if that applies to your situation, though, since you only declare a function whose return type is incomplete, which is allowed. See the attendant question by James; hopefully we'll get a definite answer there.
Just forward-declare
terminal
:You can forward-declare anything that only needs to be an incomplete type. Incomplete types can be used to form pointers, references, function signatures. The complete type only needs to be known when variables of that type are used.
Base
类不需要了解Derived
类的任何信息。这是面向对象设计的一个重要原则。您可以将基类更改为:现在,
first()
返回指向基类的指针向量。通过多态性,每个指针实际上都可以指向派生类。请注意,我将其更改为使用指针。如果您将其更改为简单的vector
,则不起作用。或者,如果您确实需要基类知道派生类的存在,您可以向前声明派生类:
Base
class should not need to know anything aboutDerived
class. That's an important principle in Object Oriented Design. You could potentially change the base class to be:Now,
first()
returns a vector of pointers to the base class. With polymorphism, each pointer can actually point to the derived class. Note that I changed it to use pointers. If you changed it to simplyvector<symbol>
that wouldn't work.Alternatly, if you really need the Base class to know about the existence of the Derived class, you can forward declare the derived class:
使用前向声明。
James - 注意声明与实例不同。这段代码工作正常
Als - 你是对的。
Use forward declarations.
James - note declarations differ from instantion. This code works fine
Als - You are correct.
我认为奇怪的重复模板模式可以让你摆脱这个:
I think Curiously Recurring Template Pattern can get you out of this one:
考虑使用返回迭代器范围的
begin()
和end()
函数,而不是让单个成员函数返回容器,类似于标准库容器本身所做的事情:如果您已经在要迭代的地方有一个
std::vector
,您只需typedefterminal const*terminal_iterator;
(或使用类似的 typedef)并定义成员相应地发挥作用。如果您没有容器(即成员函数将具体化序列本身),您可以考虑编写自己的迭代器类来生成序列。
提供
begin()
和end()
范围访问器有时比简单地为容器提供访问器要多做一些工作,但范围访问器可以提供更大的灵活性和抽象性。Rather than having a single member function return a container, consider having
begin()
andend()
functions that return an iterator range, similar to what the Standard Library containers do themselves:If you already have a
std::vector<terminal>
somewhere that you are going to be iterating over, you can justtypedef terminal const* terminal_iterator;
(or use a similar typedef) and define the member functions accordingly.If you don't have a container (i.e., the member function would materialize the sequence itself), you can consider writing your own iterator class that generates the sequence.
Providing
begin()
andend()
range accessors is sometimes a bit more work than simply providing an accessor for a container, but range accessors make for greater flexibility and abstraction.前向声明+智能指针(尽管这现在将把东西存储在堆上而不是堆栈上......可能是不可取的)
Forward declaration + smart pointer (although this will now store things on the heap instead of stack... could be undesirable)