如何避免"'标识符'使用未定义的class / struct / union' name'"前向声明不够时出错?

时间:2012-04-27 17:44:13

标签: c++

根据http://msdn.microsoft.com/en-us/library/9ekhdcxs(v=vs.80).aspx

  

如果您尝试在前向声明仅在范围内的类型的堆栈上声明对象,也会发生C2079。

class A;

class B {
    A a;   // C2079
};

class A {};
     

可能的解决方案:

class A;

class C {};

class B {
   A * a;
   C c;
};
class A {};

我的问题是如何在遇到以下情况时消除此错误:

class A;  // Object

class B   // Container
{
   public:
     typedef int SomeTypedef;
   private:
     A a;   // C2079
};

class A {
   void Foo(B::SomeTypedef);
};

在声明B之前我无法声明A,因为A需要使用B的typedef,并且由于此错误,我无法在A之前声明B.

一种可能的解决方案是使用指向A而不是堆栈变量的指针,但我不想要指针(在这种情况下)。

另一个解决方案是不使用typedef,或者不将它放在B类中。但是如果它属于B并且我不想污染我的项目的命名空间,就像B :: SomeTypedef是一个比SomeTypedef更合适的名称?

3 个答案:

答案 0 :(得分:3)

您的设计是有问题的,尽管可能是您想要的嵌套类:

class B {
   public:
     typedef int SomeTypedef;
   private:
     class A {
       void Foo(SomeTypedef);
     };
     A a;
};

如果没有,这也可以通过CRTP代码中常见的另一个类来解决。

template<typename T>
struct foo;

class A;
class B;

template<>
struct foo<B> {
  typedef int SomeTypedef;
};

class A {
   void Foo(foo<B>::SomeTypedef);
};

class B : foo<B> {
   private:
     A a;
};

或者您可以使用其他命名空间。

答案 1 :(得分:3)

另一种方法是使用中间类,加上指针,它更长,但是,它起作用:

这是头文件,(是的,我知道,“* .hpp”扩展名不是标准的):


ForwardClassExample.hpp

class ForwardClass {
public:
  virtual void DoSomething();
};

class ContainerClass {
   ForwardClass* Item;

   /* constructor */ ContainerClass();
   /* destructor */ ~ContainerClass();
};

class RealClass: ForwardClass {
  /* override */ virtual void DoSomething();
};

这是正文:


ForwardClassExample.cpp

/* constructor */ ContainerClass::ContainerClass()
{
  // create reference to forwaded class item
  this.Item = new RealClass();
}

/* destructor */ ContainerClass::~ContainerClass()
{
  // deletereference to forwaded class item
  free this.Item();
}

void ForwardClass::DoSomething()
{
  // ...
}

void RealClass::DoSomething()
{
  // ...
}

注意:

我建议习惯将指针应用于变量,而不是直接字段,在开始时它可能看起来更难,但最终还是可以做更多的事情。

它还准备你使用“引用”,以防有一天你必须使用其他编程语言。

干杯。

答案 2 :(得分:1)

介绍设计所需的typedef,然后将其导出到对用户最有意义的地方。

class A
{
public:
   typedef int SomeTypedef;
   void Foo(SomeTypedef);
};

class B
{
public:
   typedef A::SomeTypedef SomeTypedef;
private:
   A a;
};