这两个相同吗?
代码1:
class B;
class A {
public:
B fun1() const;
B* m_b;
};
extern void myfun( const B& b );
代码2:
class A {
public:
class B fun1() const;
class B* m_b;
};
extern void myfun( const class B& b );
或者代码2中是否存在使用编程风格的问题点?
答案 0 :(得分:4)
如果你有一个封闭的范围,这些是不同的。
案例1:
class B { };
namespace test {
class B; // declares test::B
class A {
public:
B fun1() const; // refers to test::B
B* m_b; // also refers to test::B
};
class B { int x; }; // defines test::B
}
案例2:
class B { };
namespace test {
class A {
public:
class B fun1() const; // refers to ::B
class B* m_b; // also refers to ::B
};
class B { int x; }; // defines test::B
}
更多详情:
class B;
是两件事之一。它可以是重新声明,也可以是将B
名称引入当前范围的前向声明(标准的§9.1[class.name] / p2)。
class B
本身称为 elaborated-type-specifier 。当你用它来声明某些东西时,编译器首先查找一个名为B
的类型是否在范围内(§3.4.4[basic.lookup.elab] / p2,§9.1[class.name] / p3注)。如果有,则使用 elaborated-type-specifier 来引用它。
如果没有,那么它也会声明一个新名称。与前向声明的区别在于声明此新名称的范围。如果用于指定命名空间作用域函数的返回类型或参数类型,则需要在包含声明的命名空间中声明名称;否则,除了作为友元声明之外,该名称在包含声明的最小名称空间或块作用域中声明(§3.3.2[basic.scope.pdecl] / p7)。请注意,这永远不会在类范围中声明名称;换句话说,它永远不会声明一个嵌套类。
为什么使用前向声明而不是替代声明?首先,它可以在任何范围内声明名称,而不仅仅是块和命名空间范围。第二,前瞻性声明不那么脆弱。请注意,在第二种情况下,如果我在test::B
之前移动test::A
的定义,那么class B
中的test::A
突然指的是test::B
而不是{{} 1}}。第三,你真的想要记住关于声明名称放在哪个范围内的整段规则吗?