How much functionality is “acceptable” for a C++ s

2019-03-18 04:05发布

My first post so please go easy on me!

I know that there's no real difference between structs and classes in C++, but a lot of people including me use a struct or class to show intent - structs for grouping "plain old data" and classes for encapsulated data that has meaningful operations.

Now, that's fine but at what point do you start to think that something isn't just a struct anymore and should become a class?

Things I think are reasonable for structs to have:

  1. constructors with simple initialisation code only.
  2. serialization code such as stream insertion / extraction operators.

Things I'm not so sure about, but would probably do:

  1. comparison operators
  2. Simple transformation functions - for example byteswapping all the members after receiving data from an external source.

I don't think structs should have:

  1. dynamic memory allocation.
  2. destructor.
  3. complex member functions.

Where do the boundaries lie???

Also, is it reasonable to have class instances as members of a struct? e.g.

class C {private: int hiddenData; public: void DoSomething();};

struct S {int a; float b; C c; };

S s; s.c.DoSomething();

Remember, I'm not on about what you CAN do with C++, I'm interested in what you SHOULD do when designing good software.

Thoughts?

标签: c++ oop struct
19条回答
Root(大扎)
2楼-- · 2019-03-18 04:29

My personal preference is to only use structs if there's no methods at all. If I need to add a method for any reason, it's a class.

查看更多
ゆ 、 Hurt°
3楼-- · 2019-03-18 04:30

You could look at what the Standard Library does. Everyone's favourite struct std::pair only has constructors.

I find the use of constructors with structs so convenient and natural that I can't imagine doing without them. I never give structs any other methods, but of course there may be free functions or members of other classes that take them as parameters.

查看更多
小情绪 Triste *
4楼-- · 2019-03-18 04:30

I always use structs for 'lumps of data', even if they get decorated with a constructor and sometimes comparison operators, they never get methods added to them (not even get/set methods).

I think this shows the intent of the type - a struct is just data to be operated on by other things.

查看更多
小情绪 Triste *
5楼-- · 2019-03-18 04:31

I wasn't making a distinction between member and free functions when I was thinking about the question, but I now see that this was a mistake. It now seems to me that structs should only rarely have member functions. It is pretty clear that everything in a struct should be public.

Therefore, there is generally no point in having struct member functions because any function can change the data in the struct. A member function on a struct would be a convenience rather than a necessity.

The only exceptions would be things required to be member functions for some other purpose - constructors for initialising arrays; comparisons for use with a map; things used by templates; etc.

Perhaps class and struct should be seen as opposites - a class exposes functions and hides data, whereas a struct exposes data and allows you to hide functions.

Going back to the byte swapping example:

struct S
{
    int data;
    S() {data = 1234;}
    void ByteSwap() {network::ByteSwap( &data );}
};

S s;
s.ByteSwap();

would become:

struct S
{
    S() {data = 1234;}
    int data;
};

namespace network
{
    void ByteSwap( int* i ) {/*byte swap *i*/}
    void ByteSwap( S* s ) {ByteSwap( &s->data );}

    S s;
    ByteSwap(&s);
}

This makes sense when the data and some functions do not always strongly belong together. Byte swapping would only be of interest to the network system but higher level functions can still use the struct without even knowing about low level stuff like byte swapping.

Another benefit in this case is that the related byte swapping operations are all kept together in the same place.

查看更多
时光不老,我们不散
6楼-- · 2019-03-18 04:33

My simple rule of thumb for structs and classes:

if (data_requires_strict_alignment == TRUE) {
  use(struct);
} else {
  use(class);
}

That is, if the data you are representing corresponds to some data object that has strict member order and alignment requirements (for example, a data structure exchanged with hardware on the driver level), use a struct. For all other cases, use a class. Classes have so many features and capabilities that structs do not, and in my experiences it is beneficial to use classes whenever possible, even if you are not using any of those additional features at the moment (if nothing else, a data-only class is like a struct with a safer default access level). Reserve structs for those cases when you need the unique properties of a struct; namely, the ability to specify structure members in a precise order and with precise alignment/padding (typically with low-level communication, e.g. drivers) such that you can cast it to a byte array, use memcpy() on it, etc. If you follow this model, then a class would not be used as a member of a structure (since a class definition does not specify alignment or a predictable value for sizeof(class)). Likewise, if you are thinking about constructors or operators, use a class.

This rule of thumb also helps make it easier to interface with C code, since structs are used in a manner consistent with C structures.

查看更多
你好瞎i
7楼-- · 2019-03-18 04:34

Consistency is most important. The point of conventions are to give a common point of reference for all those reading your code in the future.

Personally, I avoid structs if I feel I need the functionality of a class.
AKA: "plain old data" approach.

Look at your project and set a standard, or adhere to the one already there.

Though, I suggest you try to avoid inheritence, especially if all the struct is doing is holding POD. Nothing worse then tracing a bunch of super classes for an integer or char.

查看更多
登录 后发表回答