Thread: Using an unnamed enum as parameter of class constructor.

  1. #1
    Registered User
    Join Date
    Sep 2020
    Posts
    15

    Using an unnamed enum as parameter of class constructor.

    I'm learning C++ while working on a GUI for my console based program.
    I have one class 'Tab' which so far has a single constructor that takes no arguments and builds the layout I specified.
    I want to use the same class and build a different layout by calling a different constructor. This is what I had in mind:
    Code:
    int main(int argc, char **argv)
    {
        Tab proc_tab(Tab::Process);
        Tab export_tab(Tab::Export);
    
        ...
        window.addTab(proc_tab.get() );
        window.addTab(export_tab.get() );
    }
    Where Process and Export are unnamed public enums in Tab, defined in the class' body as:
    Code:
    public: enum {Process, Export}
    The problem is the constructor declaration won't accept the enums as valid types. e.g this ends up in errors:
    Code:
    Tab(Process);
    Tab(Export);
    ~Tab();
    Is there a way to achieve what I want?
    Thanks.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    That's because enumerators are values, not types, so you'll have to provide a single (declared explicit) constructor that has a parameter of that enumeration type, then say, use a switch on the enumerators.

    Note that C++ also has enum classes (scoped enumerations) that are more strongly typed (and scoped, but you're already scoping your enum).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Sep 2020
    Posts
    15
    Thanks!
    I gathered as much before posting, but wanted to hear from a knowledgeable person if there was a way around it, as I quite liked the whole arrangement.
    In any case, it turns out your solution is more convenient due to some shared code between both tabs. So is better to use a single base constructor to initialize common elements and call a local initializer for each specific case.

    Btw, what is the "established" way to let these new initializer functions or sub-constructors if you will, access private members of the class. Should I add them as private member functions (don't like it), use the "friend" system or pass a pointer to the class?

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Exosomes
    Btw, what is the "established" way to let these new initializer functions or sub-constructors if you will, access private members of the class. Should I add them as private member functions (don't like it), use the "friend" system or pass a pointer to the class?
    You should provide private member functions. Why don't you like them? They are better than friend functions because, like non-private member functions, friend functions extend the interface of the class, hence once you provide them, you have to be very careful not to change them in ways that could cause incompatibility with client code, whereas you can freely change or remove private member functions whenever you fancy, with the cost being the need to recompile client code (which you also incur when changing non-private member functions and friend functions).

    Even better than private member functions in this respect would be non-member functions declared in an unnamed namespace (roughly equivalent to static functions from C), but these do not get access to the non-public members, so they are not applicable here. Passing a pointer to the class won't work: merely having a pointer to an object of the class does not provide access to the private members.

    Quote Originally Posted by Exosomes
    In any case, it turns out your solution is more convenient due to some shared code between both tabs. So is better to use a single base constructor to initialize common elements and call a local initializer for each specific case.
    This suggests that you might want to go back to your original idea of having different layout types, but this time you make the layouts into a class hierarchy, and then your Tab class can have different layout-based constructors that delegate to a common constructor. For example:
    Code:
    class Layout
    {
    public:
        virtual ~Layout() = default; // or pure virtual, but then you still have to define it
        // ...
    protected:
        Layout() = default; // unnecessary if you make the destructor pure virtual
    };
    
    class ProcessLayout : public Layout
    {
        // ...
    };
    
    class ExportLayout : public Layout
    {
        // ...
    };
    
    class Tab
    {
    public:
        explicit Tab(const ProcessLayout& layout) : Tab()
        {
            // initialisation specific to Tab objects with a ProcessLayout
            // ...
        }
    
        explicit Tab(const ExportLayout& layout) : Tab()
        {
            // initialisation specific to Tab objects with an ExportLayout
            // ...
        }
    
        // ...
    private:
        Tab()
        {
            // initialisation common to all Tab objects
            // ...
        }
    };
    Of course, I'm assuming that it makes sense to have a layout hierarchy because there are things common to all layouts, and things specific to each layout subclass. It may well be overkill, in which case the idea of just providing enumerators and having a switch in a single constructor that delegates to non-virtual private member functions would be better.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Sep 2020
    Posts
    15
    Wow, many thanks for your thorough and detailed response! This site is definitely a welcome change from Stack Overflow.

    I've nothing against private function members, in fact that's what I ended up using. It's just that I wanted something more local. I'm missing how in C, I can have many little functions in a source file without the outside world having knowledge or having to declare them in a header. I tried to use something akin, and learned in C++ static function members can only access other static members. It was a surprise at first but in a broader view, it makes sense.

    I quite like your layout scheme. I'm saving it for a future revision since for now, I'm going with the simpler, already implemented solution as I need to be done with this already.

    Thanks again for your help,
    cheers!

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Exosomes
    I've nothing against private function members, in fact that's what I ended up using. It's just that I wanted something more local. I'm missing how in C, I can have many little functions in a source file without the outside world having knowledge or having to declare them in a header.
    You can use static non-member functions in C++ exactly as you do in C, except that the conventional approach in C++ is to use non-member functions defined within an unnamed namespace instead. Either way, they are not able to access the private members of a class, so while you can use them, you cannot use them in this context.

    Quote Originally Posted by Exosomes
    I tried to use something akin, and learned in C++ static function members can only access other static members.
    Static functions in C, static non-member functions in C++, and non-member functions defined within an unnamespace namespace all serve the same purpose: to define functions that are specific to the given translation unit and hence are very suitable for use as helper functions that do not form part of the interface of the component. Static member functions are an entirely different thing: they specify that the member function pertains to the class itself rather than to objects of the class.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. class with enum and constructor
    By antirain in forum C++ Programming
    Replies: 1
    Last Post: 05-29-2013, 02:08 PM
  2. two parameter in a constructor
    By freddyvorhees in forum C++ Programming
    Replies: 18
    Last Post: 07-25-2008, 11:31 PM
  3. Base Class Constructor parameter has a struct
    By cloudy in forum C++ Programming
    Replies: 6
    Last Post: 11-10-2007, 02:24 PM
  4. Logical parameter in parent constructor
    By g4j31a5 in forum C++ Programming
    Replies: 4
    Last Post: 11-29-2006, 04:20 AM
  5. Constructor with Parameter not Firing
    By BillBoeBaggins in forum Windows Programming
    Replies: 4
    Last Post: 08-26-2004, 02:17 PM

Tags for this Thread