Simple Multiclass C++ Project So I'm working through a beginners C++ book and they had this example demonstrating class hierarchy, which was originally in a single file. I tried recreating it with multiple files (header files + source files) to test my understanding, but I wanted to make sure that I did everything in the &quot;optimal&quot; way. Specifically, I had to use more #includes than I thought I would need to, so I'm wondering if I can make improvements there. Here is what the project looks like:
main.cpp
#include &quot;FDeepDishPizza.h&quot;
#include &lt;iostream&gt;
using std::cout, std::endl;

int main()
{
    cout &lt;&lt; &quot;Hello world!&quot; &lt;&lt; endl;
    FDeepDishPizza deepPizza(12, 13, 14, 15);
    deepPizza.DumpDensity();
    return 0;
}


FrozenFood.h
#ifndef FROZENFOOD_H_INCLUDED
#define FROZENFOOD_H_INCLUDED

class FrozenFood {
private:
    int Price;

protected:
    int Weight;

public:
    FrozenFood(int APrice, int AWeight);
    int GetPrice();
    int GetWeight();
};


#endif // FROZENFOOD_H_INCLUDED

FrozenFood.cpp
#include &quot;FrozenFood.h&quot;
#include &lt;iostream&gt;
using std::cout, std::endl;

FrozenFood::FrozenFood(int APrice, int AWeight) {
    Price = APrice;
    Weight = AWeight;
}

int FrozenFood::GetPrice() {
    cout &lt;&lt; Price &lt;&lt; endl;
}

int FrozenFood::GetWeight() {
    cout &lt;&lt; Weight &lt;&lt; endl;
}


FrozenPizza.h
#ifndef FROZENPIZZA_H_INCLUDED
#define FROZENPIZZA_H_INCLUDED

#include &quot;FrozenFood.h&quot;

class FrozenPizza : public FrozenFood {                  
protected:
    int Diameter;
public:
    FrozenPizza(int APrice, int AWeight, int ADiameter);
    void DumpInfo();
};


#endif // FROZENPIZZA_H_INCLUDED

FrozenPizza.cpp
#include &quot;FrozenPizza.h&quot;
#include &lt;iostream&gt;
using std::cout, std::endl;

FrozenPizza::FrozenPizza(int APrice, int AWeight, int ADiameter) :
    FrozenFood(APrice, AWeight) {
    Diameter = ADiameter;
}

void FrozenPizza::DumpInfo() {
    cout &lt;&lt; &quot;\tFrozen Pizza Info:&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;\t\tWeight: &quot; &lt;&lt; Weight &lt;&lt; &quot; ounces&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;\t\tDiameter: &quot; &lt;&lt; Diameter &lt;&lt; &quot; inches&quot; &lt;&lt; endl;
}


FDeepDishPizza.h
#ifndef FDEEPDISHPIZZA_H_INCLUDED
#define FDEEPDISHPIZZA_H_INCLUDED

#include &quot;FrozenPizza.h&quot;

    class FDeepDishPizza : public FrozenPizza {         //public inherit from FrozenPizza, which itself inherits FrozenFood
    private:
        int Height;
    public:
        FDeepDishPizza(int APrice, int AWeight, int ADiameter, int AHeight);
        void DumpDensity();
    };
    
    #endif // FDEEPDISHPIZZA_H_INCLUDED

FDeepDishPizza.cpp
#include &quot;FDeepDishPizza.h&quot;
#include &lt;iostream&gt;
using std::cout, std::endl;

FDeepDishPizza::FDeepDishPizza(int APrice, int AWeight, int ADiameter, int AHeight) :
    FrozenPizza(APrice, AWeight, ADiameter) {
        Height = AHeight;
    }

void FDeepDishPizza::DumpDensity() {
    cout &lt;&lt; &quot;\tDensity: &quot;;
    cout &lt;&lt; Weight * 2 &lt;&lt; &quot; pounds per cubic foot&quot; &lt;&lt; endl; //doesn't actually give density just a test
}
Don't use std::endl
Use &quot;\n&quot; instead of std::endl. The latter is equivalent to &quot;\n&quot;, but also forces a flush of the output stream, which can be bad for performance.
Don't confuse getting a value with printing a value
You have functions like int GetPrice(), that look like they return the price as an int. However, in your implementation, you actually print the price to the screen, and return nothing. Either don't print and return the price, or rename the function void PrintPrice() and return nothing.
It's usually better to just return the value instead of printing them. The caller can then decide if they want to print the value, and if so how.
Consider adding operator&lt;&lt; overloads for printing
It's always best to make classes behave like standard types. When printing something, wouldn't it be nice if you could write the following?
FrozenPizza fp(1, 2, 3);
std::cout &lt;&lt; fp;

You can if you create a friend operator&lt;&lt;(), like so:
class FrozenPizza: public FrozenFood {
    ...
    public:
    friend std::ostream &amp;operator&lt;&lt;(std::ostream &amp;os, const FrozenPizza &amp;fp);
};

std::ostream &amp;operator&lt;&lt;(std::ostream &amp;os, const FrozenPizza &amp;fp) {
    os &lt;&lt; &quot;\tFrozen Pizza Info:\n&quot;
          &quot;\t\tWeight: &quot; &lt;&lt; fp.GetWeight() &lt;&lt; &quot; ounces\n&quot;
          &quot;\t\tDiameter: &quot; &lt;&lt; fp.GetDiameter() &lt;&lt; &quot; inches\n&quot;;
}

The advantage is that you can now also &quot;print&quot; to different streams beside std::cout, like to a std::stringstream or a std::ofstream, making it much more generic.
Mark constants with const
In your classes, you initialize the member variables with some value, after which they can never be changed. In that case, make those member variables const, so that this is also clear to the compiler, which can then better optimize your code, and give an error if you accidentily do write to those variables:
class Frozenfood {
    const int Price;

protected:
    const int Weight;

public:
    ...
};

To be able to set these const variables in the constructor, use member intialization lists:
FrozenFood::FrozenFood(int APrice, int AWeight):
        Price{APrice},
        Weight{AWeight} {
}

I see you already use member initializer lists when initializing the base class, which is good.
Mark member functions that do not modify any member variables as const
Apart from making member variables const, you can also make member functions const. This tells the compiler that these functions do not change any member variables, which allows it to generate better code, produce errors if you do accidentily make changes, and allows those functions to be called on const objects.
So for example:
class FrozenFood {
    ...
    int GetPrice() const;
    int GetWeight() const;
};

int GetPrice() const {
    return Price;
}

int GetWeight() const {
    return Weight;
}

Consider using #pragma once
You are using header guards correctly. However, it can be a chore to add #ifndef..#define..#endif, and it is easy to accidentily copy&amp;paste the header guard and forget to change the name. All major compilers support #pragma once. If you add that to the header files, the compiler will ensure it's only ever included once.
However, as pointed out by others, it is not standard C++ (yet). Also, C++20 introduces modules, which avoids the need for header guards.