#include <iostream>
#include "elephant.hpp"
#include "sorting.hpp" // <-- you don't need to look at this file
int main() {
std::cout << "An Elephant occupies " << sizeof(Elephant) << " bytes\n\n";
std::cout << "## Creating array of Elephants\n\n";
constexpr size_t HSIZE = 7;
Elephant herd[HSIZE] = {{"Nellie", 7},
{"Kandula", 8},
{"Dumbo", 2},
{"Horton", 3},
{"Heffalump", 12},
{"Peanut", 1},
{"Mahmud", 9}};
std::cout << "\n## Before sorting\n\n";
for (size_t i = 0; i < HSIZE; ++i) {
herd[i].storyToStream(std::cout);
}
std::cout << "\n## Sorting Elephant array\n\n";
sortElephantsByName(std::begin(herd), std::end(herd));
std::cout << "\n## After sorting\n\n";
for (size_t i = 0; i < HSIZE; ++i) {
herd[i].storyToStream(std::cout);
}
std::cout << "\n## Destroying elephant array\n\n";
return 0;
}
#ifndef ELEPHANT_INCLUDED_HPP
#define ELEPHANT_INCLUDED_HPP
#include <cstddef>
#include <array>
#include <string>
#include <iostream>
class Elephant {
public:
Elephant();
Elephant(const std::string& name, int age);
Elephant(const Elephant& other);
~Elephant();
Elephant& operator=(const Elephant& rhs);
void remember(std::string event);
void storyToStream(std::ostream& out) const;
std::string name_ = "<unnamed>";
int age_ = -1;
private:
size_t numMemories_ = 0;
std::array<std::string, 100> memories_;
};
#endif // ELEPHANT_INCLUDED_HPP
#include "elephant.hpp"
#include <iostream>
using namespace std;
Elephant::Elephant() {
cout << "Elephant default constructor, created " << name_ << endl;
remember("I'm ");
}
Elephant::Elephant(const std::string& name, int age) : name_{name}, age_{age} {
cout << "Elephant parameterized constructor, created " << name_ << " (age "
<< age_ << ") " << endl;
remember("I arrived on the scene at age " + std::to_string(age));
}
Elephant::Elephant(const Elephant& other)
: name_{other.name_},
age_{other.age_},
numMemories_{other.numMemories_},
memories_{other.memories_} {
cout << "Elephant copy constructor, duplicated " << name_ << endl;
remember("Those are memories of a past self. I'm a copy of that Elephant.");
}
Elephant::~Elephant() {
remember("My time was up.");
cout << "Elephant destructor, destroyed " << name_ << " (with "
<< numMemories_ << " memories)" << endl;
}
Elephant& Elephant::operator=(const Elephant& rhs) {
std::string oldname = name_;
cout << "Elephant assignment, assigned " << rhs.name_
<< " into space that had held " << oldname << endl;
name_ = rhs.name_;
age_ = rhs.age_;
numMemories_ = rhs.numMemories_;
memories_ = rhs.memories_;
remember("Assignment! I was transferred into space that had held "
+ oldname);
return *this;
}
void Elephant::remember(std::string event) {
memories_[numMemories_++] = event;
}
void Elephant::storyToStream(std::ostream& out) const {
out << name_ << " (age " << age_ << ") remembers..." << std::endl;
for (size_t i = 0; i < numMemories_; ++i) {
out << "\t- " << memories_[i] << std::endl;
}
}
// NOTE: You DON'T need to understand this file, it just exists to provide
// the sortElephantsByName() and sortElephantPtrsByName() functions.
#ifndef SORTING_HPP_INCLUDED
#define SORTING_HPP_INCLUDED
#include <algorithm>
#include "elephant.hpp"
inline void sortElephantsByName(Elephant* begin, Elephant* end) {
std::sort(begin, end,
[](const Elephant& lhs, const Elephant& rhs) {
return lhs.name_ < rhs.name_;
});
// You DON'T NEED TO KNOW THIS, but here's an explanation of this line
// std::sort is a function that takes a range of elements and sorts them,
// The range is specified by the begin and end pointers. The third
// argument is a "function object" that is used to compare two elements.
// A function object is an object that can be used as if it were a
// function, which is achieved by overloading the function call operator.
//
// The [](...) { ...body... } syntax is called a lambda expression. It's
// a way to create a function object (a functor) on the fly. The code
// above is equivalent to the following:
//
// struct Lambda {
// // operator() is the function call operator, defining this operator
// // allows instances of the Lambda class to be used as if they were
// // functions.
// void operator()(const Elephant& lhs, const Elephant& rhs) {
// return lhs.name_ < rhs.name_;
// }
// };
// Lambda tempHelperObject;
// std::sort(begin, end, tempHelperObject);
//
// operator() is the function call operator. It's what gets called when
// you use the object as a function. The above code is equivalent to:
}
inline void sortElephantPtrsByName(const Elephant** begin, const Elephant** end) {
// ^-- Our use of inline here is another advanced feature outside the scope
// of CS 70. It's a hint to the compiler that it should inline the
// function. It's not required, but it can help performance. But that's
// not actually why I'm using it here. I used it here because it let
// me get away with declaring and defining the function in a header file.
// Normally functions need their own .cpp file, but inline functions are
// an exception to that rule. This allowed me to just have one file not
// to look at rather than two. But if you're reading this, you're already
// looking at it, so so much for that. Anyway, the point is that you don't
// need to understand the inline keyword, and I probably shouldn't have
// used it here. But I did, so now you know. Cue NBC meme.
std::sort(begin, end,
[](const Elephant* lhs, const Elephant* rhs) {
return lhs->name_ < rhs->name_;
});
}
#endif // SORTING_HPP_INCLUDED