What .NET Developers Must Know about C++ Classes: Listing 6
Initializer lists used in structs and user-defined containers.
#include <iostream>
#include <string>
#include <sstream>
#include <initializer_list>
#include <algorithm>
#include <vector>
using namespace std;
// unless specified otherwise, everything in a struct gets public access:
struct Person {
string firstName, lastName;
// concatenates first and last name, with a space in between
string getFullName() {
stringstream ss;
ss << firstName << ' ' << lastName;
return ss.str();
}
};
// a common functionality for a list of Person. Not instantiable.
class AbstractPersonList {
protected:
// Pure virtual function that pushes elements to the list
virtual void push_back(Person p) = 0;
// reusable function to be called by derived constructors. It fills the list with the
// STL initializer_list of Person received as parameter
inline void initStorage(initializer_list<Person> personList) {
// this is a C++11 notation known as a range-based for loop.
// Iterates over the parameter, pushing every Person element to the list
for (Person p : personList)
push_back(p);
}
};
// Person list implementation over an STL vector
class VectorPersonList : public AbstractPersonList {
private:
vector<Person> storage_;
protected:
inline void push_back(Person p) { storage_.push_back(p); }
public:
// Initializer-list constructor.
VectorPersonList(initializer_list<Person> personList) {
initStorage(personList);
}
inline vector<Person>::iterator begin() { return storage_.begin(); }
inline vector<Person>::iterator end() { return storage_.end(); }
};
// Person list implementation over a primitive array Person[]
class ArrayPersonList : public AbstractPersonList {
private:
size_t size_;
Person* storage_;
protected:
inline void push_back(Person p) {
static size_t index = 0;
storage_[index++] = p;
}
public:
// Initializer-list constructor.
ArrayPersonList(initializer_list<Person> personList) :
size_{personList.size()}, storage_{nullptr} {
if (size_>0) {
// allocates storage space based on the initializer list size
storage_ = new Person[size_];
initStorage(personList);
}
}
// A destructor is needed to release any memory allocated at construction
~ArrayPersonList() {
if (storage_!=nullptr)
delete[] storage_;
}
Person* begin() { return storage_; }
Person* end() { return storage_ + size_; }
};
int main() {
// C++03 scope of initializer-lists: structs and classes. Notice that the
// assignment ('=' sign) is optional.
Person moe = { "Moe", "Howard" }, larry = { "Larry", "Fine" },
shemp{ "Shemp", "Howard" }, curly{ "Curly", "Howard" };
// In C# this is equivalent to:
// Person moe = new Person { firstName = “Moe”, lastName = “Howard” };
// C++11 initializer-list enhancement: array-like notation that initializes
// the list calling the type initializer-list constructor
VectorPersonList vpl = { moe, larry, shemp };
ArrayPersonList apl = { moe, curly, larry };
// In C#, if the type implements IEnumerable, this is equivalent to:
// ArrayPersonList apl = new ArrayPersonList { moe, curly, larry };
// range-based for loop over the vector-based list
// Prints:
// Hello Moe Howard!
// Hello Larry Fine!
// Hello Shemp Howard!
for (Person p : vpl)
cout << "Hello " << p.getFullName() << '!' << endl;
// range-based for loop over the array-based list
// Prints:
// Hello Moe Howard!
// Hello Curly Howard!
// Hello Larry Fine!
for (Person p : apl)
cout << "Hello " << p.getFullName() << '!' << endl;
}
About the Author
Diego Dagum is a software architect and developer with more than 20 years of experience. He can be reached at [email protected].