none
How to initialize an array field in C++ class?

    Question

  • Hi,

     

    I am trying to initialize an array member of C++ class like this

     

    public class QCGatewayAdapter

    {

    public:

    QCGatewayAdapter() : test("test")

    {

    }

    char test[];

    };

     

    Got a compile error that says:

    Error 2 error C2536: QicLinkGatewayAdapter::QCGatewayAdapter::test' : cannot specify explicit initializer for arrays.

     

    I also tried using test('t', 'e', 's', '\0') and test({'t', 'e', 's', '\0'}) instead of test("test"). Didn't work either. Same error.

     

    So what should I do to initialize an array?

     

    Thanks in advance!

     

    Feng

    Tuesday, December 04, 2007 2:17 AM

Answers

  • There is actually no (standard) C++ way of dealing with this. Array initializers do not exist for classes. Thus, you are stuck with the old-style functions such as 'memset()', 'memcpy()' and the character array routines such as 'strcpy()' and so on. Furthermore, you need to specify a size for the array as well. Something along the lines:

    Code Block

    class foo

    {

    public:

      foo()

      {

        strcpy(a, "test");

      }



    private:

      char a[5];

    };



    As you can see...this is still error-prone based on the requirement of knowing the size of the array beforehand. As far as I know, Visual Studio 2005 allows some default initialization with the following line:


    Code Block

    class foo

    {

    public:

      foo() : a()


    private:

      char a[5];

    };



    But this certainly is not standard and thus I would not encourage this. Furthermore, it does not allow you to set a value...

    Since you are using C++ why not use the standard 'string' class instead. No need about initialization or memory management at all:


    Code Block

    #include <string>


    class foo

    {

    public:

      foo() : s("test") {}


    private:

      std::string s;

    };





    Tuesday, December 04, 2007 2:35 AM
  • Feng: part of the problem you are dealing with is that the C code is very strange: code like:

     

    (char **) "baseInvoiceNumber",

     

    Is pretty meaningless - casting something that is explicitly a const char* (which a string literal is) to char ** (which it most certain is not) may work in C (which is very permissive) but it will not, in general, work in C++.

     

    So instead of looking for a direct one-to-one mapping for code like this it might be better if you came up with equivalent, but different, C++ code - though in the case if the initialization above I have a hard time imaging what that would be.

     

    Tuesday, December 04, 2007 5:49 AM
    Moderator
  • You need to define the static data-member: it looks like you are trying to do that but you haven't got the syntax correct. It should be:

     

    Code Block

    char QCGatewayAdapter::segmentsep = <initial-value>;

     

     

    This is pretty basic-stuff - so maybe a day or so spent refreshing your C++ knowledge may save you some time in the long run?

    Tuesday, December 04, 2007 11:50 PM
    Moderator

All replies

  • There is actually no (standard) C++ way of dealing with this. Array initializers do not exist for classes. Thus, you are stuck with the old-style functions such as 'memset()', 'memcpy()' and the character array routines such as 'strcpy()' and so on. Furthermore, you need to specify a size for the array as well. Something along the lines:

    Code Block

    class foo

    {

    public:

      foo()

      {

        strcpy(a, "test");

      }



    private:

      char a[5];

    };



    As you can see...this is still error-prone based on the requirement of knowing the size of the array beforehand. As far as I know, Visual Studio 2005 allows some default initialization with the following line:


    Code Block

    class foo

    {

    public:

      foo() : a()


    private:

      char a[5];

    };



    But this certainly is not standard and thus I would not encourage this. Furthermore, it does not allow you to set a value...

    Since you are using C++ why not use the standard 'string' class instead. No need about initialization or memory management at all:


    Code Block

    #include <string>


    class foo

    {

    public:

      foo() : s("test") {}


    private:

      std::string s;

    };





    Tuesday, December 04, 2007 2:35 AM
  • Thank you again Andreas for the advise! The reason why I can't use string is because that I am actually converting a large C program into a C++ class. I figure, the less code I have to change, the better my chance will be to have the code working without a major re-write. Another reason I can't use string is that that my char test[] is just, well, a test. The real array I am dealing with is much more complicated. For example, here are two them that are giving me big headache:

     

    char **valid820indxnames[] = {

    (char **) "baseInvoiceNumber",

    (char **) "baseGroupNumber",

    (char **) "baseInoicePeriod",

    (char **) "baseSystemInstance",

    (char **) "\0" };

     

    void **gwidlinelist[][2] ={

    (void **) "<gwid>",

    (void **)&genchar,

    (void **) &gwidheadlnk,

    (void **) &frompunct1,

    (void **) "</gwid>",

    (void **)&genchar,

    (void **) "\0" };

     

    Imagine I have to convert these initialization into C++!

     

    Plus, you are right, the size of array is another big issue. Our existing C code relies on the dynamic size...

     

    Any more recommendations?

     

    Thanks again for your valueable inputs. You are the true MVP!

     

    Feng

    Tuesday, December 04, 2007 3:18 AM
  • Feng: part of the problem you are dealing with is that the C code is very strange: code like:

     

    (char **) "baseInvoiceNumber",

     

    Is pretty meaningless - casting something that is explicitly a const char* (which a string literal is) to char ** (which it most certain is not) may work in C (which is very permissive) but it will not, in general, work in C++.

     

    So instead of looking for a direct one-to-one mapping for code like this it might be better if you came up with equivalent, but different, C++ code - though in the case if the initialization above I have a hard time imaging what that would be.

     

    Tuesday, December 04, 2007 5:49 AM
    Moderator
  •  Feng26 wrote:
    Any more recommendations?


    Feng,

    Sorry for the late response....but yes...as Jonathan indicated...this C code is pretty...well....weird. I do not know the rest of the code but looking at the two arrays here already gives me a shudder of what the remaining code may look like.

    What I usually advise people that are in a similar situation like you (converting some C code to C++) is to not try to simply add some classes here and there (and end up with a C program using classes) but rather take the time and convert it correctly to a true C++ application using available paradigms (such as object-orienting, classes, separation, encapsulation etc.).

    I certainyl understand that this is harder than simply adding some classes and get it through the C++ compiler somehow however, in the long run you gain much more from doing it right in the beginning. Most of the times these kind of programs results in the so-called "Spaghetti'" code (any bugfix/iteration of the software makes it more obscure and complicated).
    Tuesday, December 04, 2007 2:41 PM
  • Jonathan,

     

    Thank both to you and Andreas for all your advises. You are absolutely right. The C code is ugly. To make it worse, it is also huge and the author has long gone...

     

    I do have the re-writing approach as an option, but for now I am just hard coding those array size and using assignment in constructor instead of initializer...

     

    The converted C++ class seems compile clean now. But here is another issue:

     

    I created a managed wrapper C++ class to expose the coverted  C++ class to the rest of the system. But when I conpile them, I am getting link errors from the Wrapper that all point to the numanaged C++ class' static members (the C code has static variables and in my converted class I still keep them static). The errors looks like this:

     

    Error 94 error LNK2020: unresolved token (0A00004B) "public: static char QicLinkGatewayAdapter::QCGatewayAdapter:Tongue Tiedegmentsep" (?segmentsep@QCGatewayAdapter@QicLinkGatewayAdapter@@2DA)     QCGatewayInvoker.obj

     

    Here, the QCGatewayAdapter is the converted unmanaged C++ class, QCGatewayInvoker is the wrapper class and the segmentsep is the static member defined in QCGatewayAdapter like this:

     

    public class QCGatewayAdapter

    {

    ...

    public:

    static char segmentsep;

    ...

    };

    char segmentsep;

     

    Do you see anything I am doing wrong here?

     

    Thanks again!

     

    Feng

    Tuesday, December 04, 2007 11:46 PM
  • You need to define the static data-member: it looks like you are trying to do that but you haven't got the syntax correct. It should be:

     

    Code Block

    char QCGatewayAdapter::segmentsep = <initial-value>;

     

     

    This is pretty basic-stuff - so maybe a day or so spent refreshing your C++ knowledge may save you some time in the long run?

    Tuesday, December 04, 2007 11:50 PM
    Moderator
  • Thanks Jonathan! That's it!

     

    You are the man!!!

     

    You are absolutly right. I have been working with VB.Net and C++ for quite a few years but I am not a C/C++ programer at all. I wish I could go to a trainning or something before picing up this task, but, in reality, I couldn't. So here I am with 2 C books one C++.Net book and as much on line help as I could get and try to work my way through it. Thanks to guys like you and Andreas, the help from you guys has made my life so much easier...

     

    Thanks again!

     

    Feng

    Wednesday, December 05, 2007 2:39 PM
  • I mean VB and C#, not C++, of course...

    Wednesday, December 05, 2007 4:18 PM
  • Hi Jonathan,

     

    Here is a special data member that the class name qulification didn't work for me (for all the other hundreds of different types, it worked fine). It is an array of structs that defined as static. I tried it this way:

     

    public class QCGatewayAdapter

    {

    ...

    public:

    static struct

    {

    ...some struct members...

    } validindxnames[5];

    ...

    };

    struct

    {

    ...same struct members repeat here...

    } QCGatewayAdapter::validindxnames[5];

     

    But then I get the compile error:

     

    Error 89 error C2371: 'validindxnames' : redefinition; different basic types 

     

    I also tried different formats in both places but unable to get it to compile. What am I doing wrong here?

     

    Thanks!

     

    Feng

    Wednesday, December 05, 2007 5:38 PM
  • You can't do this - you need to give the type a name. Something like:

     

    Code Block

    class QCGatewayAdapter {

    public:

       struct S {

       };

     

       static S validindxnames[5];

    };

     

    QCGatewayAdapter::S QCGatewayAdapter::validindxnames[5];

     

     

    I'l repeat my earlier comment - this is all very basic stuff and you really need to take the time to learn C++ otherwise you are going to be always facing issues like this and having to ask questions on a forum and then wait for a response it 1) not very productive and 2) is not always guaranteed to give you the result you want. In particular while we can usually solve syntactic problems (like the questions you have asked so far) we are much less informed when it comes to semantic questions as we just can't have the full necessary knowledge of what your application is actually attempting to do in order to be able to give a correct and accurate response.

    Wednesday, December 05, 2007 6:46 PM
    Moderator
  • Hi Jonathan,

     

    Finally, I got it all compiled clean, thanks to all your help!

     

    Lifeng

    Wednesday, December 05, 2007 8:41 PM