How is it that a forward declaration can hide a dependency and cause user code to skip a necessary recompilation? (google style guide c++)
Asked Answered
G

0

3

Forward declarations can hide a dependency, allowing user code to skip necessary recompilation when headers change.

from https://google.github.io/styleguide/cppguide.html#Forward_Declarations

I have learned recently there is some debate over whether to use a forward declare or just include the header within the header itself. At work we forward declare our internal classes (not library code) and include the headers containing those classes in the corresponding .cpp. If the code in the .cpp never uses the class then the include can be skipped entirely; eg it passes a type.

say we have the following code and files

#pragma once
//test.h
class Test{ 
public:
    void foo() const;
};
//test.cpp
#include<iostream>
#include "test.h"
void Test::foo() const
{
    std::cout << "test" << std::endl;
}
#pragma once
//worker_function.h
class Test;
void doWork(const Test&);
//worker_function.cpp
#include"worker_function.h"
#include"Test.h"
void doWork(const Test& obj){
   obj.foo(); //must include for compilation
}
#pragma once
//myclass.h
class Test;
class MyClass{
public:
    void passthrough(const Test& obj);
};
//myclass.cpp
#include "myClass.h"
#include "worker_function.h"

void MyClass::passthrough(const Test& obj){
   doWork(obj);
}

MyClass never actually needs to know the size of Test to get to doWork(). So, we don't need an include of Test.h. Only the actual function that does work (doWork) will need to include within its cpp. By using forward declarations, changes to Test.h will not cause any recompilation of MyClass.cpp. But in my view this is a good thing, because it is not a necessary recompilation.

Disclaimer: The google style guide has an example related to void*, but I'm not sure it is related to this bullet point; as it is just an incorrect function call rather than a necessary recompilation. Also, I believe that particular example would be eliminated if the function was defined in the .cpp instead and they included the appropriate classes. Additionally, if it is related to the bullet I have in this question, mitigation of issues related to void* do not sound valid enough to forbid the use of forward declarations entirely.

So, my question is -- is there any concrete example of a case where it will skip a necessary recompilation?

edit: This is not a duplicate of linked post as that answer only includes a void* response. I stated in this question that I am looking for any other example from the void* given. IMO that is a pretty esoteric issue (hopefully isn't common in modern c++) to completely throw out using forward declarations entirely. It seems to me like creating a rule to never use references, including pass by reference, because class member references can easily yield dangling references via default copy

Gerontocracy answered 31/1, 2020 at 1:14 Comment(1)
This is not a duplicate of linked post as that answer only includes a void* response. I stated in this question that I am looking for any other example from the void* given. IMO that is a pretty esoteric issue (hopefully isn't common in modern c++) to completely throw out using forward declarations entirely. It seems to me like creating a rule to never use references, including pass by reference, because class member references can easily yield dangling references via default copy.Gerontocracy

© 2022 - 2024 — McMap. All rights reserved.