| Lesson 3 | A safe array |
| Objective | Grouping arrays in a class |
#include <array>
#include <iostream>
class Student {
public:
std::string name;
int age;
};
int main() {
std::array<Student, 3> students{{
{"Alice", 20},
{"Bob", 22},
{"Charlie", 21}
}};
for (const auto& s : students) {
std::cout << s.name << " is " << s.age << " years old.\n";
}
}
#include <vector>
#include <string>
#include <iostream>
class Book {
public:
std::string title;
int year;
};
int main() {
std::vector<Book> library = {
{"The Hobbit", 1937},
{"1984", 1949},
{"Dune", 1965}
};
library.emplace_back("Neuromancer", 1984);
for (const auto& b : library) {
std::cout << b.title << " (" << b.year << ")\n";
}
}
#include <span>
#include <iostream>
class Point {
public:
int x, y;
};
void printGroup(std::span<Point> group) {
for (const auto& p : group) {
std::cout << "(" << p.x << "," << p.y << ")\n";
}
}
int main() {
Point points[] = {{1,2}, {3,4}, {5,6}, {7,8}};
printGroup(points); // All points
printGroup({points, 2}); // First 2 only
}
#include <tuple>
#include <string>
#include <iostream>
class Engine { /*...*/ };
class Wheels { /*...*/ };
class Body { /*...*/ };
int main() {
std::tuple<Engine, Wheels, Body> car;
auto& [e, w, b] = car; // Structured binding in C++17+
}
#include <ranges>
#include <vector>
#include <iostream>
struct User {
std::string role;
std::string name;
};
int main() {
std::vector<User>
| Technique | Use Case | Ownership | Feature |
|---|---|---|---|
std::array |
Fixed size, known at compile time | Owns data | C++11+ |
std::vector |
Dynamic size, resizable | Owns data | C++98+ |
std::span |
Views into existing arrays | No | C++20+ |
std::tuple |
Group different class types | Owns data | C++11+ |
| Ranges/Views | Functional-style grouping/filter | No | C++20–23 |
class vect as a member of the class pair_vect.
Using a class as a member of another class is known as the has-a relationship. Complicated objects can be designed from simpler ones by incorporating them with the has-a relationship.
#include "vect.h" //the safe array class
//from the previous lesson
class pair_vect {
public:
pair_vect(int i) : a(i), b(i), size(i){ }
int& first_element(int i);
int& second_element(int i);
int ub()const {return size -1;}
private:
vect a, b;
int size;
};
int& pair_vect::first_element(int i){
return a.element(i);
}
int& pair_vect::second_element(int i)
{ return b.element(i);}
pair_vect constructor is a series of initializers. The initializers of the vect members a and b invoke vect::vect(int). Let's use the pair_vect class to build a table of age and weight relationships.
int main()
{
int i;
pair_vect age_weight(5); //age and weight
cout << "table of age, weight\n";
for (i = 0; i <= age_weight.ub(); ++i) {
age_weight.first_element(i) = 21 + i;
age_weight.second_element(i) = 135 + i;
cout << age_weight.first_element(i) << ","
<< age_weight.second_element(i)<< endl;
}
}