Eckel Vol1,pg283,不完整的类型规范,编译器在做什么?

时间:2012-06-22 10:44:16

标签: c++

struct X;

struct Y {
  void f(X*);
};

struct X { //definition
private:
  int i;
public:
  friend void Y::f(X*);
  <SNIP'd>
};
  

“struct Y有一个成员函数f(),它将修改X类型的对象。这是一个难题,因为 C ++编译器要求您声明在您可以引用它之前的所有内容,因此必须先声明struct Y,然后才能将其成员Y::f(X*)声明为struct X中的朋友。但对于Y::f(X*)要声明struct X必须首先声明!

     

这是解决方案。请注意Y::f(X*)获取X对象的地址。这很关键,因为编译器总是知道如何传递一个地址,无论传递的对象是什么,它都是固定大小的,即使它没有关于类型大小的完整信息。 “

所以我们在这里:

struct X; struct Y { ... }; struct X { ... };

我的问题是:

  1. 为什么编译器坚持认为X不完整地声明为:struct X; ??

    毕竟,正如作者所说:“编译器总是知道如何传递地址 这是一个声明告诉编译器X是一个结构并且很快就会遵循的声明,所以为什么编译器如此坚持你输入字母:struct {{1}毕竟我本身没有使用X?那时没有生成汇编语言代码。当它读取X时肯定可以告诉它是一个地址(指针) ..为什么:X*需要?

    声明函数的重点是在实际之前进行类型检查 用法。所以,如果我这样做:

    struct X;

    并且编译器会发出嚎叫声。但是在上面,如果我不说: int foo(void); foo(30); 它有什么区别?他只是检查我的struct X;(函数名称)的拼写吗?

  2. 为什么不反转struct Y和X的位置有效?像这样:
    X
    我明白了:

      

    错误:无效使用不完整类型struct Y; struct X { ... }; struct Y { ... };

    显然,编译器对我的不完整类型规范不满意 'struct main()::Y'Y)。但是缺少什么珍贵的小信息?后 所有结构struct Y;;应告诉编译器Y即将遵循(与执行相同) 我们在Q1中做了什么:Y

  3. 为什么作者将结构struct X; struct Y {}; struct X{};称为定义?如果我做: X这肯定是宣言?当我实例化的时候 像这样的结构:struct X { ... }; foo;那么它是一个定义?正确的吗?

  4. 我该怎么做:

    X

2 个答案:

答案 0 :(得分:2)

  

为什么编译器坚持认为X不完整地声明为:struct X ??毕竟,正如作者所说:“编译器总是知道如何传递一个固定大小的地址......”

你没有:这也有效:

struct Y { void f(struct X*); };

class X {
    int i;
    friend void Y::f(X*);
};

您建议使用 else

此外,除非实际定义方法,否则在传递值时甚至不必具有完整类型:

struct Y { void f(struct X); };

// too early:    
void Y::f(struct X) { /* whoops compile error */ }

class X {
    int i;
    friend void Y::f(X);
};

// ok here:
void Y::f(X) { /* compile success */ }

答案 1 :(得分:1)

  

毕竟,正如作者所说:“编译器总是知道如何传递一个固定大小的地址..”这只是一个声明告诉编译器X是一个结构并很快就会遵循的原因,为什么编译器是如此坚持你输入字母:struct X;毕竟我不使用X本身?当时没有生成汇编语言代码..当它读取“X *”时,它肯定会告诉它是一个地址(指针)..为什么:struct X;需要?

作者并没有告诉你所有令人讨厌的细节。如果知道什么类型的对象X,编译器知道如何传递指针(地址)。该语言允许一些指针,如指向word-adressable机器上的char指针,或指向函数的指针,具有不同的大小。

因此,您必须告诉编译器Xstruct而不是内置类型的函数或typedef。