This is related to some other questions, such as: this, and some of my other questions.
In this question, and others, we see we can declare and initialise string arrays in one nice step, for example:
const char* const list[] = {"zip", "zam", "bam"}; //from other question
This can be done in the implementation of a function with no bother, or in the body of a .cpp file, outside any scope.
What I want to do is to have an array like this as as member of a class I am using, something like this:
class DataProvider : public SomethingElse
{
const char* const mStringData[] = {"Name1", "Name2", "Name3", ... "NameX"};
public:
DataProvider();
~DataProvider();
char* GetData()
{
int index = GetCurrentIndex(); //work out the index based on some other data
return mStringData[index]; //error checking and what have you omitted
}
};
But, the compiler complains and I can't seem to work out why. Is it possible to declare and initialise an array like this in one step in a class definition? Are there alternatives that are better?
Use the keyword static and external initialization to make the array a static member of the class:
In the header file:
class DataProvider : public SomethingElse
{
static const char* const mStringData[];
public:
DataProvider();
~DataProvider();
const char* const GetData()
{
int index = GetCurrentIndex(); //work out the index based on some other data
return mStringData[index]; //error checking and what have you omitted
}
};
In the .cpp file:
const char* const DataProvider::mStringData[] = {"Name1", "Name2", "Name3", ... "NameX"};
The reason you can't declare your array like that (const char* []) is that:
you can't have initializers in the class declaration, and so
the syntax const char* [] does not state how much space the compiler needs to allocate for each instance (your array is declared as instance variable).
Besides, you probably want to make that array static, since it is in essence a constant value.
This is not possible in C++. You cannot directly initialize the array. Instead you have to give it the size it will have (4 in your case), and you have to initialize the array in the constructor of DataProvider:
class DataProvider {
enum { SIZEOF_VALUES = 4 };
const char * values[SIZEOF_VALUES];
public:
DataProvider() {
const char * const v[SIZEOF_VALUES] = {
"one", "two", "three", "four"
};
std::copy(v, v + SIZEOF_VALUES, values);
}
};
Note that you have to give up on the const-ness of the pointers in the array, since you cannot directly initialize the array. But you need to later set the pointers to the right values, and thus the pointers need to be modifiable.
If your values in the array are const nevertheless, the only way is to use a static array:
/* in the header file */
class DataProvider {
enum { SIZEOF_VALUES = 4 };
static const char * const values[SIZEOF_VALUES];
};
/* in cpp file: */
const char * const DataProvider::values[SIZEOF_VALUES] =
{ "one", "two", "three", "four" };
Having the static array means all objects will share that array. Thus you will have saved memory too.
Related
This question already has answers here:
Undefined reference to static class member
(9 answers)
Closed 8 years ago.
I am trying to find a way that I can define/initialize some static string arrays in a struct inside a class definition. These string arrays are always to be initialized with string literals. I tried doing the following and it initializes the parameterTypes[] fine and i can access the strings using eg. MethodNaming_bla::parameterTypes[2], but if I pass the parameterTypes as a const char* const * const i get a linker error :( Also if i pass it to a constructor using MethodNaming_bla::parameterTypes.
struct MethodNaming_bla
{
static constexpr const char* const parameterTypes[] = { "afd","qwer","zvc" };
static const char* const * const parameterTypes_d = parameterTypes;
};
However if i do the same in a function, it works for some reason.
int main(int, char* [])
{
static constexpr const char* const parameterTypes[] = { "afd","qwer","zvc" };
static const char* const * const parameterTypes_d = parameterTypes;
}
Is there a way where I can define and initialize a string array in a struct from string literals, inline?
Thanks in advance,
Martin
Ok, thanks for your comments. Kerrek, the dublicate u mention explain why it doesnt work, but it does not solve my problem for me, because I need the initialization to be inline - initalizing it in the implementation file is therefore not an option for me.
Guess my only option is something like:
struct MethodNaming_bla
{
static const char* const * const ParameterTypes()
{
static const char* const parameterTypes[] = { "afd","qwer","zvc" };
return parameterTypes;
};
};
I have some C code that I'm trying to convert/wrap into a C++ class. I ran into some C literal arrays(correct me if I'm calling them wrong) and I'm not sure how to initialize them in the C++ constructor since I don't think you can do literals, which I think are compile time specific, to something that is runtime specific.
Should I just explicitly define the array to be of a certain size and just do a strcpy, or some such, of the literal to the array in the constructor?
char sysUpTime[] = {1,3,6,1,2,1,1,3,0};
As an alternative to initializer lists or string manipulation, you could use something like the following (if you really wanted to):
struct Wrapper
{
template <size_t N>
Wrapper(const char(&arr)[N]) : vec(arr, arr+N) { }
vector<char> vec;
};
I've left everything public due to chronic laziness on my part :). You can then initialise like this:
char foo[] = { 1, 2, 3, 4, 5 };
Wrapper bar(foo);
copy(bar.vec.begin(), bar.vec.end(), ostream_iterator<int>(cout, ", "));
Could just use std::string to store OID then initialize it in member initializer list for example:
#include <string>
class Wrapper
{
public:
Wrapper() : sysUpTime("1.3.6.1.2.1.1.3.0") { }
private:
std::string sysUpTime;
};
Or use C++11 std::array
class Wrapper
{
public:
Wrapper() : sysUpTime{{1,3,6,1,2,1,1,3,0}} { }
public:
std::array<char, 10> sysUpTime;
};
The main problem when passing different size c-style arrays to a constructor is that you must pass the size along with it. Here's an example of putting the array into a member vector:
#include <vector>
#include <iostream>
struct Test
{
std::vector<char> sysUpTime;
Test(const char sysUpTime[], size_t size) :
sysUpTime(sysUpTime, sysUpTime + size)
{ }
};
int main()
{
const char sysUpTime[] = {1,2,3,4,5};
Test test(sysUpTime, sizeof(sysUpTime) / sizeof(char));
}
Unfortunately I know of no way to do this without using a dynamic array (vector), aside from using templates which means that you'll get a separate class instantiated for each and every change in the size of your array.
In Visual C++, how can I initialise a constant array inside of a class?
This is an example of how to do it outside of a class:
const char k_colors[] =
{
'R',
'G',
'B',
};
Now how do I need to change that? (I tried putting static in front of it, which didn't work)
Edit: You're right, I should just use single characters.
If you want it to be static, you'll need to initialize it outside the class:
class foo
{
public:
static const char k_colors[3];
foo() { }
};
const char foo::k_colors[] = {'a', 'b', 'c'};
Also, you probably want it to be a const char *[] since it looks like you're trying to initialize strings, so it'd be:
const char *foo::k_colors[] = {"Red", "Green", "Blue"};
I tried putting static in front of it, which didn't work
You can't initialise the static member array (or any member array) inside the class definition. Do it outside of the class definition:
class X
{
static const char* k_colors[3];
};
const char* X::k_colors[] = { "Red", "Green", "Blue" };
In C++11 you can use the constructor initializer list as mentioned
class A {
const int arr[2];
// constructor
A()
: arr ({1, 2})
{ }
};
Or you can use static const array
In header file:
class A {
static const int a[2];
// other bits follow
};
In source file (or in separate place from the declaration above)
const int A::a[] = { 1, 2 };
Of course you can always use std::vector<int> and for loop as well.
I think you can initialize through the constructor initializer list
Refer here
Also the char should be char*
Extract from the above link:
prior to C++11 you need to do just this to default-initialise each element of the array:
: k_colors()
With C++11 it is more recommended use uniform initialisation syntax:
: k_colors{ }
And that way you can actually put things into the array which you couldn't before:
: k_colors{"red","green"}
I have a class called CoolMenuItems
class CoolMenuItems
{
public:
CoolMenuItems();
~CoolMenuItems();
struct MenuItemOne
{
int id;
uint32 type;
uint32 subtype;
String name;
};
struct MenuItemTwo
{
uint32 subtype;
String name;
};
}
This is just the bare bones of the class... I want to have two arrays, one of MenuItemOne, and one of MenuItemTwo, and these arrays would have the following. These arrays I want to initialize like:
MenuItemOne a[] =
{
{1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")},
{2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS, EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")},
};
MenuItemTwo b[] =
{
{EQData::EQ_FILTER_TYPE_TRHU, T("Thru")},
{EQData::EQ_FILTER_TYPE_BUTTERWORTH_6DB, T("6 dB Butterworth")},
};
only, with more elements than just two...
I want to set it up so that I can create a new CoolMenuItems object with
CoolMenuItems *cmi = new CoolMenuItems();
so that I can access those array elements via
cmi->a[1];
Can you modify your code like this
class CoolMenuItems
{
public:
CoolMenuItems();
~CoolMenuItems();
struct MenuItemOne
{
int id;
uint32 type;
uint32 subtype;
String name;
};
struct MenuItemTwo
{
uint32 subtype;
String name;
};
std::vector<MenuItemOne> menuItemOne;
std::vector<MenuItemTwo> menuItemTwo;
}
So that you can initialize the elements of struct and push_back the struct into the std::vector, all the memory to be allocated and to be freed will be taken care of by the std::vector
MenuItemOne a = {1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0,T("Parametric")};
menuItemOne.push_back(a);
Similarly for MenuItemTwo.
If you have a different requirement then please give more details.
Initialization of member variables are somewhat tricky in C++, so my recommendation would be something like the following:
MenuItemOne& ret_a(int i)
{
static MenuItemOne a[] =
{
// definition of a[]
};
return a[i]; // maybe with some bounds checking
}
Note that this has some advantages. First, declaring the array a as static inside a class method makes it globally defined just once. Second, you hide the actual a[] array behind a method call, which is a better design practice.
EDIT
As the arrays cannot be static, as the values depend on some other library, the values have to be set up at some point, say the CoolMenuItems constructor:
CoolMenuItems::CoolMenuItems()
{
for (int i = 0; i < A_ITEMS; ++i)
{
a[i].id = X;
a[i].name = T("xxx");
}
// ...
}
or, if you have to put the values by hand:
CoolMenuItems::CoolMenuItems()
{
a[0].id = X;
a[0].name = T("xxx");
a[1].id = ...
// ...
}
This is tedious, but can be automated with some editor usage, or preprocessor. Note also that you then have to declare the ret_a function similarly and declare the corresponding a and b arrays within the class:
MenuItemOne a[A_ITEMS];
MenuItemTwo b[B_ITEMS];
With enough time, I'd give you a nice elisp macro to be used within emacs to generate all the initializations from the C arrays you wrote :)
I have a class and I want to have some bit masks with values 0,1,3,7,15,...
So essentially i want to declare an array of constant int's such as:
class A{
const int masks[] = {0,1,3,5,7,....}
}
but the compiler will always complain.
I tried:
static const int masks[] = {0,1...}
static const int masks[9]; // then initializing inside the constructor
Any idea on how this can be done?
Thanks!
class A {
static const int masks[];
};
const int A::masks[] = { 1, 2, 3, 4, ... };
You may want to fixate the array within the class definition already, but you don't have to. The array will have a complete type at the point of definition (which is to keep within the .cpp file, not in the header) where it can deduce the size from the initializer.
// in the .h file
class A {
static int const masks[];
};
// in the .cpp file
int const A::masks[] = {0,1,3,5,7};
enum Masks {A=0,B=1,c=3,d=5,e=7};
you can initialize variables only in the constructor or other methods.
'static' variables must be initialized out of the class definition.
You can do this:
class A {
static const int masks[];
};
const int A::masks[] = { 1, 2, 3, 4, .... };
Well, This is because you can't initialize a private member without calling a method.
I always use Member Initialization Lists to do so for const and static data members.
If you don't know what Member Initializer Lists are ,They are just what you want.
Look at this code:
class foo
{
int const b[2];
int a;
foo(): b{2,3}, a(5) //initializes Data Member
{
//Other Code
}
}
Also GCC has this cool extension:
const int a[] = { [0] = 1, [5] = 5 }; // initializes element 0 to 1, and element 5 to 5. Every other elements to 0.