1

I can't find the answer anywhere.

I wrote this class:

class Message {
private:
    char senderName[32];

    char* namesOfRecipients[];

    int numOfContacts;

    char subject[129];

    char body[10001]; 
};

And I'm trying to write a constructor with default arguments like this:

Message(char senderName[32]="EVA",
        char* Recipents[]={"glados","edi"},
        int numOfRec=3,
        char subject[129]="None",
        char content[10001]="None");

However, it won't accept the recipients default argument no matter how I write it.

Is it even possible to pass a 2D array as a default argument for a constructor?

Ziezi
  • 6,375
  • 3
  • 39
  • 49
  • 4
    I don't know if this is possible, but have you tried with `const`? i.e. `const char subject[129] = "None"`. Also, why not use `std::string` and `std::vector` for recipients (since you're using c++)? – simon Dec 29 '15 at 18:30
  • `const char* Recipents[]` should work – Angelus Mortis Dec 29 '15 at 18:31
  • Hi, im not allowed to use strings or vectors. Regardless, I can't see why a lack of const is the problem... – Daniel Nahmias Dec 29 '15 at 18:34
  • @DanielNahmias Because [allowing a string literal to be stored as non-const char* is deprecated](https://stackoverflow.com/questions/9650058/deprecated-conversion-from-string-literal-to-char) also see [here](https://stackoverflow.com/questions/1524356/c-deprecated-conversion-from-string-constant-to-char) – Cory Kramer Dec 29 '15 at 18:36
  • `char* namesOfRecipients[];` This is not valid C++. Zero-sized arrays are not allowed, const or no const.. – PaulMcKenzie Dec 29 '15 at 18:37
  • adding const doesnt work... is there a valid way to do it? – Daniel Nahmias Dec 29 '15 at 18:38
  • No. This is one of the many reasons why `std::string` was created. – Lightness Races in Orbit Dec 29 '15 at 18:41
  • 5
    *Hi, im not allowed to use strings or vectors.* -- I'm not allowed to use my legs to walk. That is basically what you're requirements are stating. – PaulMcKenzie Dec 29 '15 at 18:42
  • @DanielNahmias When you say "it won't accept..." you should add an error message that the compiler outputs. Maybe it looks really clear to you what exactly the compiler doesn't like, but other people here need a demonstration. – anatolyg Dec 29 '15 at 19:25
  • @PaulMcKenzie "I'm not allowed to use `std::string` nor `std::vector`" is a perfectly normal design constraint for a C++ program. In fact, in my experience "we don't use anything from `std::` ever" is far more common than the alternative. – zwol Dec 29 '15 at 23:17

4 Answers4

3

Sooo many pointers and arrays... if It is C++ why bother? Just write:

class Message {
private:
    std::string senderName;

    std::vector<std::string> namesOfRecipients;

    int numOfContacts;

    std::string subject;

    std::string body; 
};

And:

Message("EVA", {"glados","edi"}, 3, "None", "None");

And everbody is happy...

fatihk
  • 7,789
  • 1
  • 26
  • 48
  • Couldn't have said better ! Why using C++ and not using it's standard libary containers that make things really easy ? I don't get it... – kebs Dec 31 '15 at 10:34
0

As Paul mentioned, you should change the declaration of namesOfRecipients to

 char **namesOfRecipients;

Then you can have a private const static array of default names in the class and initialize namesOfRecipients with a pointer to its first element. The code is below.

Edit: It's important to understand what the data semantics are here, for example compared to Jarod's solution. The default ctor stores the address of an array of constant pointers to constant character strings. It's not at all possible to copy different characters into a name or to let one of the pointers in the array point to a new name, or to append a name. The only legal thing here is to replace the value of namesOfRecipients with a pointer to a new array of pointers to char.

class Message {
private:
    char senderName[32];

    char** namesOfRecipients;

    int numOfContacts;

    char subject[129];

    char body[10001]; 
    static const char* defaultNames[];
    public:
    Message(const char senderName[32]="EVA",
        const char** Recipents = defaultNames,
        int numOfRec=3,
        const char subject[129]="None",
        const char content[10001]="None");
};

const char *Message::defaultNames[] = {"Jim", "Joe"};
Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
-1

You can do something like:

namespace
{

    char (&defaultSenderName())[32]
    {
        static char s[32] = "EVA";
        return s;
    }

    const char* (&defaultNamesOfRecipients())[2]
    {
        static const char* namesOfRecipients[2]={"glados", "edi"};
        return namesOfRecipients;
    }

}

class Message {
private:
    char senderName[32];
    const char* namesOfRecipients[2];

public:
    Message(char (&senderName)[32] = defaultSenderName(),
            const char* (&namesOfRecipients)[2] = defaultNamesOfRecipients())
    {
        std::copy(std::begin(senderName), std::end(senderName), std::begin(this->senderName));
        std::copy(std::begin(namesOfRecipients), std::end(namesOfRecipients), std::begin(this->namesOfRecipients));
    }
};

but using std::string/std::vector would be simpler.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I assume that the number of recipients is not permanently 2, which makes it more appropriate to hold a pointer (or, of course, a vector). Apart from that it is important to notice the different semantics -- the copying you do allows to change the names *in situ* (my solution doesn't), but doesn't allow to have more recipients. – Peter - Reinstate Monica Dec 29 '15 at 19:28
-1

Use a separate array of pointers (it's not a 2-D array, though it may look like it) as a default argument:

char* defaultRecipents[] = {"glados","edi"};

class Message {
public:
    Message(char senderName[32]="EVA",
            char* Recipents[]=defaultRecipents){}
};

Specifying the default array "inline" doesn't work because the compiler "thinks" about it in terms of std::initializer_list, which is only suitable in initialization, not in declaration. Sorry if this sounds vague; I don't have enough experience with this matter.

Note: you might want to use const to declare your strings, to make it clear to the compiler (and your future self) whether the class is or is not going to alter the strings:

const char* const defaultRecipents[] = {"glados","edi"};

class Message {
public:
    Message(char senderName[32]="EVA",
            const char* const Recipents[]=defaultRecipents){}
};

Here it says const twice to declare that it's not going to:

  1. Change the array elements (e.g. replace one array element, which is a string, by another string or nullptr); and
  2. Change the contents of the strings (e.g. cut a string in the middle, or edit it)
anatolyg
  • 26,506
  • 9
  • 60
  • 134