摘自google's c++ coding guidelines。
我们如何在标题中使用类Foo 文件无法访问其定义?
- 我们可以声明Foo *或Foo&类型的数据成员。
- 我们可以使用参数声明(但不定义)函数,和/或 返回值,类型为Foo。 (一 异常是如果参数Foo或 const Foo&有一个非显式的, 单参数构造函数,其中 我们需要完整的定义 支持自动类型转换。)
- 我们可以声明Foo类型的静态数据成员。这是因为静态 数据成员在外部定义 课程定义。
我很好奇的是第二个子弹中的异常。为什么会这样?如果我们想支持自动类型转换,为什么需要完整定义?
我的猜测是编译器需要目标类型的完整定义,因为隐式转换中创建了临时对象。我猜对了吗?还有更多吗?
编辑:
正如我所看到的,指南中的例外情况是针对这样的情况:
class A
{
public:
A( int );
};
class B
{
public:
B( A const &a );
};
int main()
{
B b(2);
}
这里我们只有一个用户定义的隐式转换(从int到A),并调用接受A const&的构造函数。只有在这个例外中有意义的是支持从例如直接转换。 int到A,然后通过接受A const&的构造函数到B,允许客户端代码使用这个转换链,而不需要显式地包含声明A类的头文件。
答案 0 :(得分:2)
C ++语言不区分头文件中的代码和其他文件。它甚至不要求标题是文件。从技术上讲,这个问题毫无意义,但实际上你会限制你在头文件中所做的事情,以免违反一个定义规则。在不限制自己的情况下,用户必须小心,只将头文件包含在一个翻译单元中。通过适当的限制,头文件可以自由地包含在多个翻译单元中。
不完整类型是指大小未知的地方,其中sizeof
无法使用。
当类定义未知时,类Foo
必然是不完整的。
这意味着你无法做出需要知道大小的事情。而且由于不完整意味着成员不为人所知(如果知道他们的大小就必须知道),你通常不能召集任何成员。例外:可以调用析构函数,就像在delete pFoo
中一样,并且编译器必须接受它,但如果类Foo
具有非平凡的析构函数,则它是未定义的行为。
然而,Google指南中提到的例外情况毫无意义。
编辑:我发现,当事情详细阐述时,SO上的人会更喜欢,所以,添加为什么指南的讨论毫无意义。
指南说你可以“声明(但不定义)”但是“如果参数Foo或const Foo&具有非显式的单参数构造函数,则会出现一个例外”。
声明与构造函数没有任何关系,可以通过简单的尝试来确认:
#include <iostream>
struct Foo;
Foo bar( Foo const& ); // Declaration of function bar, works fine.
struct Foo
{
int x_;
Foo( int x ): x_( x ) {} // Converting constructor.
};
int main()
{
std::cout << bar( 42 ).x_ << std::endl;
}
Foo bar( Foo const& foo ) { return foo; }
总之,Google指南的例外情况再次毫无意义。
干杯&amp;第h。,
答案 1 :(得分:0)
假设foo.h
只知道Foo
声明
//foo.h
class Foo;
void f(const Foo &); // It is possible to use the reference.
完整定义位于foo.cpp
// foo.cpp
class CanBeConvertedToFoo;
class Foo
{
Foo (const CanBeConvertedToFoo & x); // implicit constructor
}
class CanBeConvertedToFoo
隐式可转换为Foo;
但在some.cpp
中未知。
// some.cpp
#include "foo.h"
void g(const CanBeConvertedToFoo & x) {
f(x); // Is it known about implicit conversion ?
}
答案 2 :(得分:0)
我不知道第二点的例外是否属实。隐式转换只有在调用函数时才能知道,而不是在声明函数时才知道,所以即使在C
声明f
时#include <iostream>
class C;
void f(C);
struct C { C(int i) { std::cout << "C(" << i << ")" << std::endl; } };
void f(C c) { std::cout << "f(C)" << std::endl; }
int main() { f(2); }
不完整,以下情况仍然有效:
{{1}}