Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are aggregate classes for?

Tags:

c++

I have just read the following definition in C++ Primer (5th edition) on page 298:

A class is an aggregate if:

  • All of its data members are public

  • It does not define any constructors

  • It has no in-class initializers

  • It has no base classes or virtual functions

A definition is also provided in this post: What are Aggregates and PODs and how/why are they special?.

After all I read in the previous sections of the book on the value of encapsulation, I am wondering: why would anyone want to use an aggregate class? (BTW, the question seems to be applicable to struct in general: why would I want to have public: by default?)

like image 736
AlwaysLearning Avatar asked Dec 10 '22 22:12

AlwaysLearning


2 Answers

An aggregate is basically a simple collection of data that does not have any invariants the class would have to guarantee. Since there is no invariant and thus all combinations of possible values of the member make sense, there is no point in making them private since there is nothing to protect.

A simple example for such a class would be something like

struct Point3d {
   std::array<double, 3> coordinates;
};

Since every triple of doubles is a point in R^3, there is nothing to gain by hiding the data. (If you are afraid of NaN and infinity values, this might not be the best idea. If this can happen, you might want to not make this an aggregate.)

Another example of an aggregate type is std::array. Again, it is just an array of some type and some (immutable) length, so no invariant is to protect.

One advantage of aggregates is aggregate initialization.

like image 174
Baum mit Augen Avatar answered Dec 13 '22 12:12

Baum mit Augen


Aggregate classes can be aggregate initialized using an initializer list:

struct Agg {
    string a;
    int b;
}
Agg a = {"A string", 0};

They are mainly used as a tupple-like return value like so:

struct Response {
    bool success;
    string body; // Body is only set if success is true
}

Response foo() {
    if(failed) return {false, ""};
    return {true, "content"};
}

As you can see all four requirements have to be fulfilled for this to be meaningful (before c++11).

All of its data members are public

It's pretty much just a tuple of objects.

It does not define any constructors

Well, either you initialize all members (via aggregate initialization) or you default initialize all members (with the default constructor).

It has no in-class initializers

Same as above

It has no base classes or virtual functions

It's tuple-like, so base classes would destroy that and virtual functions don't make sense since you wouldn't inherit from such a class.

I hope this clears it up a bit. Remember that this is was invented before C++11 where std::tuple wouldn't exist so you would have used an aggregate class to return multiple values. Nowadays in most use cases you could use tuple aswell but it is not my favorite.


std::tuple vs aggregate classes

  • An aggregate class can define member functions
  • An aggregate class can overload operators.
  • An aggregate can define useful names for its attributes
  • etc.. to expand

Most of the time, aggregate classes are the way to go. tuple should only be used if you really want nothing else but returning a tuple of objects, and then "breaking it into its pieces". Member functions don't make sense most of the time but aggregate classes can still overload the cast operator for example.

Use tuples only when you only want to do nothing but retuning a bunch of objects together, without a need to "name" them (via member names in aggregates)

like image 26
WorldSEnder Avatar answered Dec 13 '22 10:12

WorldSEnder