Nesting classes?

I want to be able to nest a class within a class or a struct within a struct. The reason for doing so is that if i have a class, I usually like to have functions that test out functionality of that class, but I want to keep testing stuff separate from the actual class but still be part of it, so if I were to use the object it would look something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  #include <iostream>

using std::cout;
using std::endl;

class Character
{
    public:
        Character() = default;

        class Test
        {
            public:
                Test() = default;

                void TestFunction()
                {
                    cout << "Test" << endl;
                }
        };

    private:
};

int main()
{
    Character::Test::TestFunction();
}


Although a struct would probably be more appropriate for the nested class. Also is nesting classes a good idea?
Last edited on
is nesting classes a good idea?
When used appropriately, yes.
Yes if the designed data structure requires it.
every tool has a purpose, but that said, most of the time the point of making a class is to reuse a block of code. If its buried inside something else, it is not reusable, or not as clean and easy. So you have to determine if putting it there serves a bigger, better purpose than being able to reuse the inner class's code someday.
> If its buried inside something else, it is not reusable, or not as clean and easy.

The member class (nested class) is public, so it is usable from any part of the program; as easily as any class declared within a namespace.

The name of a member class that is not public is not accessible everywhere, though there are no restrictions on accessing objects of that class type.
cppreference has this example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class enclose {
    struct nested { // private member
        void g() {}
    };
 public:
    static nested f() { return nested{}; }
};
 
int main()
{
    //enclose::nested n1 = enclose::f(); // error: 'nested' is private
 
    enclose::f().g(); // OK: does not name 'nested'
    auto n2 = enclose::f(); // OK: does not name 'nested'
    n2.g();
}

https://en.cppreference.com/w/cpp/language/nested_types
True, that is a good example of the mechanics. This falls under my 'clean and easy' caveat ... its a little wonky with the public/private as you noted, and now to find the bits you need it is, at best, in the middle of something else.

I sadly can't even remember what problem nested classes resolve that can't be done by has-a or inheritance, though, so they seem like clutter without benefit... I know there is a reason but I am going to have to revisit that.
My questions are:

What do the testing frameworks do? Do they inject the Test class, or are they separate?

Is there a way of getting rid of all the testing stuff, once it is proven that the code works as intended? I mean it is easy enough to enclose the Test class with preprocessor #ifdef, but personally I would rather not see them at all in a post tested release build.

Are there any downsides to having a separate Test class that takes a user object as an argument?
I was just looking at what cmake does:

https://cmake.org/cmake/help/v3.20/guide/tutorial/index.html#guide:CMake%20Tutorial

It has testing builtin, although in this beginners tutorial it looks basic, like static_assert using arguments to main.

There probably is more to it, like being able to test individual functions, I am guessing :+)
what problem nested classes resolve


One example is for a list class. You have a private struct for the node within the overall list class.
> I sadly can't even remember what problem nested classes resolve that can't be done by has-a or inheritance

Nested classes minimise dependencies. For example, the iterator class for a list that can only be used in conjunction with the list class would be (should be) a nested class. In the standard library, iterators are usually member classes; std::ios_base::failure is a member class etc.

Just as in real life it is a mistake to demand that every possession one has must be reusable by all and sundry in the universe, so too in software. There are many classes that are designed for restricted use.


> What do the testing frameworks do? Do they inject the Test class, or are they separate?

The test code need not have to be a class; very often, functions are good enough.
Frameworks (or libraries) which support mock testing (for example, Typemock's Isolator++ or GoogleTest's Google Mock), mock (fake) objects that simulate the behaviour of the real ones on which the code is dependant are created and added to the test code.


> Is there a way of getting rid of all the testing stuff, once it is proven that the code works as intended?

This is what I tend to do:
Say, the component is a.cpp. Create a separate test driver, say a_test.cpp (Often, the test code or class may be granted a friend status to the class being tested.) Link them along with the stubs or mock dependencies into the test frame. In the production code build, there would not be any a_test.cpp or stubs.


> Are there any downsides to having a separate Test class that takes a user object as an argument?

No. This is actually a useful technique when the behaviour of an object under different states needs to be tested; put the object into the state to be tested and pass it to the test component (sometimes along with expected results).
@JLBorges

Thanks for you always splendid & expert advice :+D
And thanks for the good examples as well. I have always just put those alongside (same file etc), but not inside, I see exactly what you mean.
Last edited on
Topic archived. No new replies allowed.