前向类声明可以与类关键字在使用位置互换吗?

4

这两个代码等效吗?

代码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 );

那么,在 Code 2 中使用的编程风格是否存在一些问题呢?

1个回答

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本身被称为精细型说明符。当您使用它来声明某个东西时,编译器首先查找是否存在名为B的类型在作用域内(标准§3.4.4 [basic.lookup.elab]/p2,§9.1 [class.name]/p3 记号)。如果有,则认为精细型说明符指的是那个类型。
如果没有,它将还声明一个新名称。与前向声明的区别在于此新名称的声明范围。如果用于指定命名空间范围内函数的返回类型或参数类型,则将其视为在包含声明的命名空间中声明该名称;否则,在除友元声明外的最小命名空间或块范围内声明该名称(标准§3.3.2 [basic.scope.pdecl] /p7)。请注意,这永远不会在类作用域中声明名称;换句话说,它永远不会声明嵌套类。
为什么要使用前向声明而不是其他方法?首先,它可以在任何范围内声明名称,而不仅仅是块和命名空间范围。其次,前向声明更加健壮。请注意,如果我将test::B的定义移到test::A之前,那么test::A中的class B将突然引用test::B而不是::B。第三,您真的想记住一个关于声明名称所在作用域的整个段落吗?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接