请教高手:两个类相互引用,无法编译。(VS 2003 .net VC++7)

icbm 2007-02-12 12:24:06
class A;
class B
{
public:
A * a;
void set(A * p){a = p};
void func1()
{
a->func2();
}
void func2()
{

}
};
class A
{
public:
B * b;
void set(B * p){b = p};
void func1()
{
b->func2();
}
void func2()
{

}
};

int main()
{
A a;
B b;
a.set(&b);
a.func1();

return 0;
}


正在编译...
Test1.cpp
g:\opengl游戏程序设计\source\chapter21\test1\test1.cpp(60) : error C2143: 语法错误 : 缺少“;”(在“}”的前面)
g:\opengl游戏程序设计\source\chapter21\test1\test1.cpp(63) : error C2027: 使用了未定义类型“A”
g:\opengl游戏程序设计\source\chapter21\test1\test1.cpp(54) : 参见“A”的声明
g:\opengl游戏程序设计\source\chapter21\test1\test1.cpp(63) : error C2227: “->func2”的左侧必须指向类/结构/联合

生成日志保存在“file://g:\OpenGL游戏程序设计\Source\chapter21\Test1\Debug\BuildLog.htm”中
Test1 - 3 错误,0 警告

不管把哪个类放在前面,都会报错。请教高手,不要改变上述类的功能,使程序编译通过。


...全文
776 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
icbm 2007-02-12
  • 打赏
  • 举报
回复

谢谢steedhorse(晨星) ( 三星(高级))啊,函数的明白了。可是问题又来了。函数可以放到后面再定义,如果是枚举型的定义呢?还是编译不通过啊,又不能放到后面。

class A;
class B
{
public:
enum EB{EB1, EB2, EB3};
A::EA ea;
};
class A
{
public:
enum EA{EA1, EA2, EA3};
B::EB eb;
};
晨星 2007-02-12
  • 打赏
  • 举报
回复
否则,像你原来那样,B类定义之前只有A类有前向声明,对于:
A * a;
void set(A * p){a = p;}
当然都没啥问题,因为a和p毕竟都是指针嘛。但对于:
void func1()
{
a->func2();
}
就不行了,编译器此时还没看到A类的完整定义,它怎么知道A类有没有一个叫做“func2”的方法呢?
HewpKanXue 2007-02-12
  • 打赏
  • 举报
回复
class A;
class B
{
public:
A * a;
void set(A * p);
void func1();
void func2();
};
class A
{
public:
B * b;
void set(B * p);
void func1();
void func2();
};
void A:: set(B * p)
{b = p;}

void B::set(A * p)
{
}

void B::func1()
{
a->func2();
}
void B::func2()
{
}

void A::func1()
{
b->func2();
}
void A::func2()
{
}

int main()
{
A a;
B b;
a.set(&b);
a.func1();
}
icbm 2007-02-12
  • 打赏
  • 举报
回复
错误举例二:调用的函数互相递归调用
class B;
class A
{
public:
B *b;
void func()
{
b->func();
}
};
class B
{
public:
A *a; // 前面这里写错了,应该改成指针。
void func()
{
a->func();
}
};
晨星 2007-02-12
  • 打赏
  • 举报
回复
然后,更主要的,你的B类的定义中调用到了A类的方法,既然方法都调用到了,而不是仅仅使用一下指向那个类对象的指针或引用,那光有前向声明就没用了。

解决的方法是,你依然可以把B类的声义放在那里,但需要把B类的func1函数的定义放到A类的后面去,让B类定义中只出现func1的声明;或者放到另一个cpp文件中,然后在那里文件中包含B类的完整定义。

放到B类后面去是指这样:
class A;
class B
{
public:
A * a;
void set(A * p){a = p;}
void func1();
void func2()
{

}
};
class A
{
public:
B * b;
void set(B * p){b = p;}
void func1()
{
b->func2();
}
void func2()
{

}
};

void B::func1() {
a->func2();
}

int main()
{
A a;
B b;
a.set(&b);
a.func1();

return 0;
}
icbm 2007-02-12
  • 打赏
  • 举报
回复
不好意思,刚才写错了。谢谢steedhorse(晨星) ( 三星(高级))指点。
class A;
class B
{
public:
A * a;
void set(A * p){a = p;}
void func1()
{
a->func2();
}
void func2()
{

}
};
class A
{
public:
B * b;
void set(B * p){b = p;}
void func1()
{
b->func2();
}
void func2()
{

}
};
icbm 2007-02-12
  • 打赏
  • 举报
回复
我认为上述两个类逻辑上是成立的。
两个类并没有相互嵌套包含,调用的函数也不存在互相递归调用。

错误举列一:两个类相互嵌套包含
class B;
class A
{
public:
B b;
};
class B
{
public:
A a;
};

错误举例二:调用的函数互相递归调用
class B;
class A
{
public:
B *b;
void func()
{
b->func();
}
};
class B
{
public:
A a;
void func()
{
a->func();
}
};

到底错在哪里,请高手指正。
晨星 2007-02-12
  • 打赏
  • 举报
回复
首先,
void set(A * p){a = p};
要改成:
void set(A * p){a = p;}
icbm 2007-02-12
  • 打赏
  • 举报
回复
我只是想弄清楚问题,究竟错在哪里,喜欢追根问底。

我举的例子只不过是经过简化后,突出问题重点的例子,并非恶搞。我问的问题也是在维护原有代码过程中发现的,并非凭空想象。当然可以通过别的方式解决,只是那样改动比较大罢了。

实际项目中,很多类是不同的人设计的,难免出现上面的问题。如果知道问题所在,即可以在编码规范中制定一条,而不是通过经验来解决这类经常出现的问题。

向steedhorse(晨星) 致敬,高手就是高手。实事求是,既能找到问题所在,也不会嘲笑特殊想法。论坛就是个不同想法交流的地方,有不同意见才会进步啊。
FingerStyle 2007-02-12
  • 打赏
  • 举报
回复
真能想...
roger_77 2007-02-12
  • 打赏
  • 举报
回复
晨星老大都说了,偶来看看

只是想说,设计良好的程序应该尽量避免这种相互引用。
如果感觉不可避免,就使用头文件声明和cpp文件定义的方式来解决。
晨星 2007-02-12
  • 打赏
  • 举报
回复
而且我前面的方法,其目的也只是了让那个函数在定义时能够看到它所需要用到的东西。而非循环引用问题的万能方法。

至于无法解决的循环引用问题,用得着这么挖空心思去想么?随便想想也能想出一堆来。
楼主你先前不是也想出过来吗?比如你前面所说的互相包含另一个类的对象(而不是指针或引用),同样也是一个无法解决的问题,这没啥好奇怪的。
晨星 2007-02-12
  • 打赏
  • 举报
回复
hoho,不会。
taodm 2007-02-12
  • 打赏
  • 举报
回复
你这叫恶搞!
不要这么做!
icbm 2007-02-12
  • 打赏
  • 举报
回复
我又想了几种类似的情况:
class A;
class B
{
public:
enum EB{EB1, EB2, EB3};
A::EA ea; // 变量类型
A::EA func1(){return A::EA1; } // 函数返回值类型
void func2(A::EA v){} // 函数参数类型
};
class A
{
public:
enum EA{EA1, EA2, EA3};
B::EB eb; // 变量类型
B::EB func1(){return B::EB1; } // 函数返回值类型
void func2(B::EB v){} // 函数参数类型
};

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧