Why use forward declarations




















Or have I missed a tiny detail that's different? It's possible, but I've visually compared a few times and can't see any Thank you! That edit adds a tonne of valuable info. I'll have to read it several times to fully understand it I suspect I'll be able to use this to reduce dependencies in various places.

Except If this external dependency is desired behaviour. Andy Dent Andy Dent That provides a sound reason not to follow your "should supply enough information to use" principle even for currently non-templated types. You are talking about when you should or shouldn't use forward declarion. That is totally not the point of this question, though. This is about knowing the technical possibilities when for example want to break a circular dependency problem. I disagree with Luc Touraille's answer So write him a comment, including a link to a blog post if you need the length.

This doesn't answer the question asked. If everyone thought questions about how X works justified answers disagreeing with X doing that or debating limits within which we should restrain our freedom to use X - we'd have almost no real answers.

Naveen Naveen This breaks encapsulation and makes code brittle. To do this, you need to know if the type is a typedef or a class for a class template with default template parameters, and if the implementation ever changes, you'll need to update ever place you've used a forward declaration. For example: the iosfwd Standard library header, which contains forward declarations of iostream content.

Patrick Glandien Patrick Glandien 7, 5 5 gold badges 38 38 silver badges 47 47 bronze badges. This makes no sense. One cannot have a member of an incomplete type. Any class's declaration must provide everything all users need to know about its size and layout. Its size includes the sizes of all of its non-static members.

Forward-declaring a member leaves users with no idea of its size. Sesh Sesh 5, 4 4 gold badges 27 27 silver badges 39 39 bronze badges. Why ever did 2 people upvote this? You're not talking about what the question is talking about. You mean normal - not forward - declaration of functions. The question is about forward-declaration of classes. Of course it won't compile. All the proper answers here explain why and the precise, limited contexts in which forward-declaration is valid.

You instead have written this about something totally different. Niceman Niceman 3 3 silver badges 7 7 bronze badges. What you've written follows directly from concepts implicit in Luc's answer, so while it would've made a good comment adding overt clarification, I'm not sure it justifies an answer.

I will just add to that why we need to use it. It needs to be rebuilt less often! The Google style guide recommends against using forward declarations, and for good reasons:. Also, notice that when we transformed a class member to a pointer, we likely had to start dealing with heap-allocated memory for each instance of Foo. If Foo needs to access its Bar pointer very often, the small overhead of a pointer indirection can add up. The Modules TS may present another safer alternative to improving build times by removing the need for the preprocessor to paste in entire headers over and over again for different translation units.

For starters, forward declarations are low-hanging fruit as far as improving build time goes. Just an intuition. So we decided to be Agile about it. I took the top headers that were most often included, and I made it a challenge to replace them with forward declarations wherever I could. If doing this improved things at all, then I could go ahead and take a more comprehensive approach. Along the way I gained even more confidence that a more comprehensive approach would yield additional gains.

This is frustrating, but on a positive note, it forces your codebase to follow a best practice — a translation unit should be self-contained.

Never should you rely on an indirect include because future refactoring efforts will needlessly break your code and cause headaches for other programmers. I got the go-ahead to spend a week touching as many headers as I could for forward declaration work. At the end of it all, I had gone though perhaps two-thirds of all header files.

The result? Plus Visual Studio stopped crashing when generating the dependency graph. This result was quite surprising, I had thought we would already start to see diminishing returns after the first go. Best practices have their flip-sides. The Google style guide and a few of my coworkers made some good points against the usage of forward declarations, but the real world results of the technique are undeniable.

The automated builds are faster. The point about memory usage becomes more important for large parallel builds. In fact, we were occasionally running out of memory, and this work has abated those issues for the time being; forward declarations are really just a band-aid on an architectural issue.

Time is money, and in a larger project with many well-paid people, saving even a small amount of time has an economy-of-scale effect; provably thousands or hundreds of thousands of dollars saved in development time. The ODR has three parts:. Violating part 1 of the ODR will cause the compiler to issue a redefinition error. Violating ODR part 2 will likely cause the linker to issue a redefinition error.

Violating ODR part 3 will cause undefined behavior. Because the above program violates ODR part 1, this causes the Visual Studio compiler to issue the following compile errors:. Functions that share an identifier but have different parameters are considered to be distinct functions.

We discuss this further in lesson 8. A declaration is a statement that tells the compiler about the existence of an identifier and its type information.

Here are some examples of declarations:. A declaration is all that is needed to satisfy the compiler. This is why int x appears in our examples for both definitions and declarations. In most cases, a definition serves our purposes, as it satisfies both the compiler and linker. We only need to provide an explicit declaration when we want to use an identifier before it has been defined. While it is true that all definitions are declarations, the converse is not true: all declarations are not definitions.

An example of this is the function prototype -- it satisfies the compiler, but not the linker. Other types of pure declarations include forward declarations for variables and type declarations you will encounter these in future lessons, no need to worry about them now.

Show Solution. The answer is: everything the compiler needs to determine the size and memory layout of the objects it has to instantiate. For everything else, forward declarations are enough. Broadly speaking, that are base classes and the types of member variables. Since every object that has a base class contains a subobject of that base class, it is clear that the base class definition is needed. For member variables we need to go into more detail: We only need class definitions of the actual types of our member variables.

The same goes for references, which are technically pointers with a few restrictions. What about function parameter and return types? No definitions needed when we only declare the functions!

Of course, if we define the functions, we actually use the parameter types and therefore also need their definitions. Here again, pointers and references are the exceptions, as long as we do not access the objects behind them.

That last function adds a dependency we could get rid of: If we only declare the function in the class definition and move the function definition to MyClass. We would then only need a forward declaration in the header. Forward declarations are not only a useful help in reducing compile times. They are also crucial to break dependency cycles.

Imagine that the class Member from the example contained a Pointer to MyClass. To compile this, the compiler needs to know what MyClass is.



0コメント

  • 1000 / 1000