0

How should I write a constructor for a class to initialize a member that is a const structure / has const fields?

In the following example, I define a constructor within structure B and it works fine to initialize it's const fields.

But when I try to use the same technique to initialize const fields of structure C within class A it doesn't work. Can someone please help me and rewrite my class A in a way, that it starts working?

#include <iostream>
class A
{
public:
    struct C
    {
            C (const int _x) : x (_x) {}
            const int x;
    };

    C c (3);

};
int main (int argc, char *argv[])
{
struct B
{
    B (const int _x) : x (_x) {}
    const int x;
};

B b (2);
std::cout << b.x << std::endl;

A a;
std::cout << a.c.x << std::endl;

return 0;
}

P.S.

  1. I did some search and I think, I understand, that unless I have C++11 support or want to use boost library, I have to define a helper function to initialize a const struct within initialization list (C++ Constant structure member initialization) but it seems to be crazy that I have to define alike struct, but with non const fields to initialize a struct with const fields, doesn't it?

  2. Another thing that I found tells that I should initialize const members in a constructor of the class A, rather than in a constructor of the struct C (C++ compile time error: expected identifier before numeric constant) but it also seems crazy to me, because why should I rewrite a class constructor every time I want to add a new struct, isn't it more convenient to have a separate constructor for each struct C within the class A?

I would be grateful to any comments that could possibly clarify my confusion.

Community
  • 1
  • 1
user1541776
  • 497
  • 4
  • 14
  • 1
    Note: your problem with class A isn't the const per-se. Remove the const from the member of C and you'll get the same issue. – Mat Jul 04 '13 at 16:19
  • @Mat, thank you for your comment. You are right. I wrote const there to make my intentions clear: I wanted to create an instance of class A, that would contain a struct C with a const field x. Moreover, I wanted to set the value of x at a run time (it's not crystal clear from my question that x = 3 is set only at a run time). Basically, my problem was "You can't initialize variable within the class scope, you need to do it in a constructor." http://stackoverflow.com/questions/6008712/c-expected-identifier-before-numeric-constant but it was not clear to me without Jerry Coffin's explanation. – user1541776 Jul 04 '13 at 18:38

1 Answers1

5

I'd do the job like this:

#include <iostream>
class A {
public:
    struct C {
        C(const int _x) : x(_x) {}
        const int x;
    };

    C c; // (3);
    A() : c(3) {}
};
int main(int argc, char *argv []) {
    A a;
    std::cout << a.c.x << std::endl;

    return 0;
}

Note that it's not a matter of using a ctor in A or in C, but of the ctor for A telling how the ctor for C should be invoked. If the value that will be passed will always be 3 that's not necessary, but I'm assuming you want to be a able to pass a value of your choice when you create the C object, and it will remain constant after that.

If the value will always be the same (3 in this case) you can simplify things a lot by also making the constant static:

struct A {
    struct C {
        static const int x = 3;
    };
    C c;
};

int main() { 
    A a;
    std::cout << a.c.x << "\n";
}

So, if the value is identical for all instances of that class, make it static const, initialize it in place, and life is good. If the value is not known until you create an instance of the object, and remains constant thereafter for the life of that object, you need to pass it in through the constructors.

For a slightly different case, there's a third possibility: if C is an independent class (not nested inside of A) you might have a situation where other instances of C use various values, but all instances of C inside an A always use the same value. In this case, you'd do something like:

struct C { 
    const int x;

    C(int x) : x(x) {}
};

struct A { 
     C c;

     A() : c(3) {}
};

Of course, you can do the same thing when C is nested inside of A, but when/if you do, it generally means you're setting the same value for all instances of C, so you might as well use the static const approach instead. The obvious exception would be if A had multiple constructors, so (for example) A's default constructor passed one value for C::x and its copy constructor passed a different value.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • thank you very much for such a detailed, thoughtful and "branched" explanation! You solved my problem with the first third of your answer and enriched my understanding of how to use classes in the other two thirds. I bet your answer will be helpful to many others and once again thank you! – user1541776 Jul 04 '13 at 18:21