1

When it comes to creating classes I've been told NO public data members. That's fine and I understand why but here's my issue. I've got a struct that I am using in a class (Linear linked list). I'd really like to initialize one of the struct fields (an array) to NULL so that I can check that the client is passing me valid structs, not uninitalized one's that are full of garbage values. I realize c++ won't let me set a default value in the struct declaration, so how do I protect from the client giving me garbage?

struct task {
    char *description;
    char *name;
    float time_remaining;
    float time_spent;
};

Then in my class I'm trying to do something like:

//I am making a copy of "to_add" and storing it in the LLL
int list::add_to_list(const task & to_add)
{ /.../ }

I don't want the user adding a bunch of uninitialized "task's" to the linked list... What to do? When I turned that struct into a class and moved the data members to private I had a TON of issues trying to access the data members to make copies of them. I was very careful not to do anything to effect the value of the var's but I couldn't get away from the compiler giving me errors about "error: passing ‘const task’ as ‘this’ argument of ‘char* task::get_comp_name()’ discards qualifiers [-fpermissive]" ("get_comp_name") was one of the getter's that I was sure wasn't editing any values, just passing me a copy) Please help me before I shoot myself. In the face.

MCP
  • 4,436
  • 12
  • 44
  • 53
  • I can't understand the problem. No public data member means the only way to access data which can be "interesting" for the "outside" world is through a getter, and if you need to set them, you must do through a setter. When an instance is created, you can initialize your private members to whatever you want. Anything passed from outside as method arguments can be potentially unsafe, but this is "normal", and I don't see how you couple it with the no-public-data requirements, they seem to me two different "facts". Can you explain better? – ShinTakezou Apr 20 '12 at 05:42
  • The error is because you didn't declare the function `const`. If you really want to provide accessors rather than public data, then the getter should be something like `char const * get_comp_name() const;`. – Mike Seymour Apr 20 '12 at 06:25

3 Answers3

4

In C++ a struct and a class are the same except for access control. So the struct's default access to members and inheritance is public, whereas the class' one is private. So you can give your struct a defult constructor and others to initialize it.

struct task {
    task() : desctiption(0), name(0), time_remaining(0.), time_spent(0.) {}
    char *description;
    char *name;
    float time_remaining;
    float time_spent;
};

One side-effect of adding a constructor is that the struct isn't an aggregate anymore. This may or may not be an issue for you.

In C++11, you are also able to initialize members at the point of declaration:

struct task {
    char *description{nullptr};
    char *name{nullptr};
    float time_remaining{0};
    float time_spent{0};
};

This in-place initialization accepts type x = y syntax too, and argument-less {} initialization results in value initialization, which results in zero initialization for primitive types, so the arguments in the example could have been omitted.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • +1. By the way, `char *name{}` is enough. similarly, `float time_spent{}`. [More here](http://stackoverflow.com/questions/10147264/braces-around-string-literal-in-char-array-declaration-valid-e-g-char-s/10147335#10147335). – Nawaz Apr 20 '12 at 05:44
  • @Nawaz Indeed, I'll add something. – juanchopanza Apr 20 '12 at 05:48
  • That's it!!! Damn I love you guys. So many smart people on here. Thanks a ton! – MCP Apr 20 '12 at 05:50
2

There are several issues at hand here.

Public or not Public ?

Public attributes can seem handy, but they usually come back to bite you when you least expect it. I already suspect an issue with the time_remaining and time_spent: I suppose that both are modified quite at the same moment, aren't they ?

By default, variable attributes should be private, so that the class may enforce invariants such as time_remaining + time_spent is a constant throughout the lifetime of the task.

It is fine for constant attributes to be public, their role in invariants is settled once and for all in the constructor anyway.

But the weird errors message ?

This is because you lack a good tutorial or book. The problem at hand is quite simple: it is a const-ness related issue.

A const object may only be passed by const-reference or value to functions/methods and only const methods may be called on it. In your case, the proper declaration of the name() method should have a const qualifier after the method name.

Putting it altogether

And throwing in std::string because it's so much easier to manipulate.

class Task {
public:
    Task(): time_remaining(0), time_spent(0) {}
    Task(std::string name, std::string desc, float duration):
        _name(name), _desc(desc), _time_remaining(duration), _time_spent(0) {}

    // Accessors
    std::string const& name() const { return _name; }
    std::string const& description() const { return _desc; }
    float time_remaining() const { return _time_remaining; }
    float time_spent() const { return _time_spent; }

    // Modifiers
    void spend(float duration) {
        _time_remaining -= duration;
        _time_spent += duration;
    }

private:
    std::string _name, _desc;
    float _time_remaining, _time_spent;
}; // class Task

Note: it could probably be beneficial to check that the duration passed to the spend method is not superior to the _time_remaining attribute, otherwise you spend more than you have...

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • That looks like a great declaration! So to the point. As far as the accessors go: since you're working with strings those accessors are just returning a copy, right? What about if you're working with an array (ie pointers)? Will that "const" after the function name be enough to let one access/make independent copy of the array? – MCP Apr 20 '12 at 15:20
  • 1
    @MCP: not, they are returning `std::string const&` which is a const-reference to the string. If the caller write `std::string const& name = t.name();` she gets a const-reference, if she writes `std::string const name = t.name();` (subtle absence of `&`) she gets a `const` value (not that the `const` is optional in the latter case). `const` on the method means that you cannot change the class internals attributes. If the class holds a pointer, then the pointer itself cannot be changed, but the object it point to may be changed if it is not `const`-qualified. – Matthieu M. Apr 20 '12 at 15:47
  • @MCP: You should look for questions on this site or tutorial to understand `const`-ness. It's a simple topic if explained properly, but it can be utterly confusing if not. Especially because it's not merely technical, but can also be used for logical `const`-ness, generally more useful, which requires some experience with the concept (and guidelines to start with). – Matthieu M. Apr 20 '12 at 15:48
  • I'll do that. This is the first time I've really started writing something that could benefit from const-ness...and I definitely don't quite understand how it works although I'm learning that's to you guys. I'll look for a tutorial. Thanks! – MCP Apr 20 '12 at 15:56
1

Implement a constructor for the struct:

struct task {
    task() : description(0), name(0), time_remaining(0), time_spent(0) {}
    char *description;
    char *name;
    float time_remaining;
    float time_spent;
};

The only difference between a class and a struct in C++ is the default accessibility of it's members.

Andreas Brinck
  • 51,293
  • 14
  • 84
  • 114
  • The other difference is default inheritance, which is public for struct and private for class. – juanchopanza Apr 20 '12 at 05:47
  • @Andreas: There is a difference between *visibility* and *accessibility* in C++. What you should write is, *accessibility*, **not** *visibility*. – Nawaz Apr 20 '12 at 05:48