前向声明是否完全消除了对指针类型的任何#including 的需要?
Does forward declaration fully remove the need for any #including for pointer types?
假设我们有一个源文件 A.cpp,我们在其中转发声明了一个 ClassB 类型,然后我们继续使用指向 ClassB 的指针,而没有 #including 文件 B.cpp(其中定义了 ClassB) ;在 B.cpp 中,我们转发声明 ClassA 并使用指向它的指针,而无需 #including A.cpp (定义 ClassA 的地方),那么编译器对此是否完全满意?符号解析会正常工作吗?换句话说,这两个目标文件是否在 link 时间之前根本不需要彼此了解?
(我假设在 visual studio 上编译 C++ 代码而不对默认编译器进行任何更改)
PS:
文件A.cpp
class ClassB;
class ClassA
{
bool JustTakeAClassBPointAndDoNothingWithIt(ClassB* class_b_pointer)
{
if(class_b_pointer)
return true;
else
return false;
return false;
}
}
文件B.cpp
class ClassA;
class ClassB
{
bool JustTakeAClassAPointAndDoNothingWithIt(ClassA* class_a_pointer)
{
if(class_a_pointer)
return true;
else
return false;
return false;
}
}
这取决于你想用指针做什么 - 你只能用指向 forward-declared 类型的指针做非常有限的事情。例如,像这样的分配就可以了:
class A;
void myFunc(A* a1)
{
A* a2 = nullptr;
A* a3 = a1;
}
但是你甚至不能 increment/decrement 它们(因为为此,编译器必须知道 object 的大小才能“走过”)。你也不能构造此类型的 object 或访问其任何方法(因为为此,编译器当然需要知道该类型是什么样的,或者它具有哪些方法)。请参阅 [= 中给出的示例11=].
关于您的问题的补充一点 - 您提到包括“B.cpp”。这表明
- 您只有一个文件同时包含声明和定义,这是不好的做法(将它们分成 .h 和 .cpp 文件!并且只包含 .h 文件!)
- 或者您实际上包含了带有定义的文件而不是 header 文件——这从来都不是必需的,除非您做错了什么;例如模板在这方面可能很棘手——它们基本上也应该在 header 中定义。
为了提供更多详细信息,您必须提供更多信息,说明您究竟想用这些 forward-declared 指针做什么。
另见
这个问题真的太笼统了,无法正确回答,但这是我的 2 美分。一般来说,只要你只引用一个class作为指向它的指针,编译就可以了。例如这个例子编译得很好:
class B;
int main() {
B * tst;
return 0;
}
但是,一旦您尝试实际实例化一个指针,或访问它的任何方法,您就需要一个完整的定义。这些例子 NOT 有效:
class B;
int main() {
B * tst = new B(); // error: allocation of incomplete type 'B'
return 0;
}
或者:
class B;
int main() {
B * tst;
tst->print(); // error: member access into incomplete type 'B'
return 0;
}
tl;博士;只要您实际上不与之交互,就可以使用不完整的类型。如果使用任何方法或函数,都需要提前声明(包括构造函数)
假设我们有一个源文件 A.cpp,我们在其中转发声明了一个 ClassB 类型,然后我们继续使用指向 ClassB 的指针,而没有 #including 文件 B.cpp(其中定义了 ClassB) ;在 B.cpp 中,我们转发声明 ClassA 并使用指向它的指针,而无需 #including A.cpp (定义 ClassA 的地方),那么编译器对此是否完全满意?符号解析会正常工作吗?换句话说,这两个目标文件是否在 link 时间之前根本不需要彼此了解?
(我假设在 visual studio 上编译 C++ 代码而不对默认编译器进行任何更改)
PS:
文件A.cpp
class ClassB;
class ClassA
{
bool JustTakeAClassBPointAndDoNothingWithIt(ClassB* class_b_pointer)
{
if(class_b_pointer)
return true;
else
return false;
return false;
}
}
文件B.cpp
class ClassA;
class ClassB
{
bool JustTakeAClassAPointAndDoNothingWithIt(ClassA* class_a_pointer)
{
if(class_a_pointer)
return true;
else
return false;
return false;
}
}
这取决于你想用指针做什么 - 你只能用指向 forward-declared 类型的指针做非常有限的事情。例如,像这样的分配就可以了:
class A;
void myFunc(A* a1)
{
A* a2 = nullptr;
A* a3 = a1;
}
但是你甚至不能 increment/decrement 它们(因为为此,编译器必须知道 object 的大小才能“走过”)。你也不能构造此类型的 object 或访问其任何方法(因为为此,编译器当然需要知道该类型是什么样的,或者它具有哪些方法)。请参阅 [= 中给出的示例11=].
关于您的问题的补充一点 - 您提到包括“B.cpp”。这表明
- 您只有一个文件同时包含声明和定义,这是不好的做法(将它们分成 .h 和 .cpp 文件!并且只包含 .h 文件!)
- 或者您实际上包含了带有定义的文件而不是 header 文件——这从来都不是必需的,除非您做错了什么;例如模板在这方面可能很棘手——它们基本上也应该在 header 中定义。
为了提供更多详细信息,您必须提供更多信息,说明您究竟想用这些 forward-declared 指针做什么。
另见
这个问题真的太笼统了,无法正确回答,但这是我的 2 美分。一般来说,只要你只引用一个class作为指向它的指针,编译就可以了。例如这个例子编译得很好:
class B;
int main() {
B * tst;
return 0;
}
但是,一旦您尝试实际实例化一个指针,或访问它的任何方法,您就需要一个完整的定义。这些例子 NOT 有效:
class B;
int main() {
B * tst = new B(); // error: allocation of incomplete type 'B'
return 0;
}
或者:
class B;
int main() {
B * tst;
tst->print(); // error: member access into incomplete type 'B'
return 0;
}
tl;博士;只要您实际上不与之交互,就可以使用不完整的类型。如果使用任何方法或函数,都需要提前声明(包括构造函数)