Home > database >  Class Inside a Class in C : Is that heavy?
Class Inside a Class in C : Is that heavy?

Time:04-01

Suppose I do something like:

class A
{
public:
    class B
    {
    public:
         void SomeFunction1() const;
         using atype = A;
    };

    using btype = B;
    void SomeFunction2() const;

private:
    B b;
};

Then I create an instance of class A and copy it:

A a;
A acopy = a;

Does that make the class A heavy, what I mean is, what happens in the background? I would hope that C doesn't really literally "consider" the definition of class B everytime I declare an instance of class A, I thin what happens in the background is that class B will be treated as a new definition under a namespace named A, so A::B is defined. My question is does defining a class inside a class (B inside A) create any overhead when declaring or copying the class A, or it's treated exactly as if B is defined outside?

Thank you everyone :)

CodePudding user response:

My own opinion is:

  • It's heavy to read, even with source code folding.
  • It's often useless: B class could be fully merged with A class most of the time.
  • Even if B if required by A, and never ever used elsewhere, it can be defined out of A. Constructors are your friends to "force" some associations - delete the default constructor, for example.
  • Inside or outside A, it doesn't change anything regarding deep copy.
  • If you need to expose B directly through A, it's a design flaw - move these functions from B to A instead.

So I really don't see, apart "sparing" a header file, what you can "gain" by declaring a class within a class...

For my part, I would prefer:

  • Use the PIMPL idiom to "hide" B, if it isn't required publicly.
  • Move everything that needs to be exposed publicly in A either permanently (move the source code), or use wrappers to the PIMPL object.
  • If you need to replace/share a B instance, change the unique_ptr for the PIMPL object to a shared_ptr instead. Take care of deep copy.

It's usually WAY more efficient, hides perfectly the B code if required (don't even need to export it from a DLL, for example), you won't recompile B at all when changing A and you can change how B work without even breaking your A API.

CodePudding user response:

C is a compiled language. We generally assume that the computers used to compile C source code are powerful enough. Compilers may reasonable use Gigabytes in the process of compiling an executable.

So when we say that something is "heavy", we usually mean that it's heavy at runtime. The runtime environment for a C program may well be a coffee maker or a fridge.

Things like name lookup in nested scopes are pure compile-time actions, and do not have any runtime impact. And modern compilers are smart enough to inline the default methods here, so there's no runtime overhead in calling members.

  • Related