This is meant to be an introduction to using Git and C++ syntax. Complete this tutorial after doing a number of HackerRank problems (especially those in Classes and Inheritance).
We will be implementing different types of convex polyhedra and computing their volumes. The goal of this assignment is not to know how to compute the volume of a Snub Dodecahedron, but to get a sense of Git and OOP in C++.
Pick and choose a [uniform convex polyhedron] (https://en.wikipedia.org/wiki/List_of_uniform_polyhedra#Convex_uniform_polyhedra) . This will be the polyhedron you implement for this project.
Head to https://github.com/ScottSWu/polyhedra, and click on the Fork button.
This will create a new repository under your own account.
Install Git. It's recommended you run in a unix-based environment.
On Windows or Mac, download and run their installer. On Linux distributions, you can use the package manager and run one of the following from the terminal:
sudo apt-get install git # Ubuntu
sudo pacman -S git # Arch
sudo yum install git-all # Fedora
Verify git
is installed by running git --version
. Then clone this repository
with:
git clone https://github.com/<your username>/polyhedra.git
A folder called polyhedra
will be created with the files from the repository.
Move to this new directory in the terminal with cd polyhedra
.
We want to create two files, a header file and source file. The header file defines the structure of your class so that other programs can use it without having to read and compile the implementation details. Those implementation details go in the source file.
- Create a file in the
include
folder and name itpolyhedron_name.h
- Create a file in the
src
folder and name itpolyhedron_name.cpp
The rest of this project will be adding your polyhedron to this repository. At
any time, feel free to refer to the snub_dodecahedron.{h, cpp}
as an example.
The purpose of the header file is to define the signature of variables and functions so that when other parts of the program want to use your code, it knows exactly what functions are available and what arguments to pass.
Open up the header file you created in your favorite editor.
Always start your header file with a header guard. A header guard is a
preprocessor definition that prevents your class from being defined twice.
Preprocessor definitions start with a #
and are executed when the code is
compiled.
Pick a unique name and add the following to your header file.
#ifndef _POLYHEDRON_NAME
#define _POLYHEDRON_NAME
...
#endif
Not all classes are available by default. We can include the header files of
classes that we need so we can use them in our header file. This time, we will
need two classes - string
and Polyhedron
.
// The angle brackets signify this is a system library
#include <string>
// The quotations signify this is a user library (in the same project)
#include "polyhedron.h"
Our new polyhedron will be a subclass of the Polyhedron
class. We use the
colon (:
) to define this.
class PolyhedronName : public Polyhedron {
};
The constructor is called when an instance is created. The destructor is called when an instance is deleted (whether it goes out of scope or explicitly deleted in code).
// Anything following this will be a public member of the class
public:
// Constructor - takes the author's name as an input
PolyhedronName(std::string author);
// Destructor
~PolyhedronName();
Since we have subclassed Polyhedron
, we can override certain virtual
functions from the original Polyhedron
class.
Take a look at polyhedron.h
from the include
folder. Copy any function with
the virtual
modifier into your own class.
virtual std::string get_name();
virtual unsigned int get_faces();
...
Now that our new polyhedron is defined in the header file, we can fill in the implementation details.
The first step in the source file is to include the header file.
#include "polyhedron_name.h"
For each function you defined in the header, we need to write an implementation. First is the constructor and destructor. The constructor needs to take in the proper parameters and also call the constructor of the super class. Feel free to define any other variables here.
PolyhedronName::PolyhedronName(std::string author) : Polyhedron(author) {
...
}
The destructor starts with a tilde, and is useful for cleaning up any memory. This will probably be empty, since we don't really have much to clean up.
PolyhedronName::~PolyhedronName() {
}
All other functions in the header file are written in a similar fashion to the constructor and destructor.
std::string PolyhedronName::get_name() {
return "Polyhedron Name";
}
Again, refer to snub_dodecahedron.cpp
if you're unsure about implementation.
Your class is now defined and implemented, but it's not actually used anywhere
yet. The final thing we want to do is edit src/polyhedron_test.cpp
to create
an instance of our polyhedron.
The first line to add is an include statement before main
referencing our
header file.
#include "polyhedron_name.h"
Then we can instantiate a new object.
// Add your name and polyhedron here!
polyhedra.push_back(std::make_shared<PolyhedronName>("Your Name"));
To compile and test your class, head back to the terminal (which should be
in the polyhedra
directory) and run make test
.
If you have any compile errors, it will point to the source in code. Fix these.
Otherwise it will print info and run tests on your polyhedron.
If all tests pass, we're good to add it to the repository. You can view all your
changed files with git status
and git diff
.
If you're satisfied with your changes, and don't see any extraneous files being
added, you can stage your files for committing by running git add -A
.
Type git status
again and you will see the changed files are now ready to be
committed.
Commit with git commit
and add your message. Alternatively you can use
git commit -m "<message>"
to add a message directly from the command line.
First, make sure your repo is up to date with the main repository. To identify
what the main repository is, run git remote -v
. origin
identifies your fork
while upstream
identifies the original repo. If there is no upstream
, add it
by running:
git remote add upstream https://github.com/ScottSWu/polyhedra.git
Now you can fetch the changes from upstream.
git fetch upstream
This will download the changes, but not apply them to your files yet. To apply, run:
git rebase upstream/master
If there are any conflicts, resolve them with the text editor. Afterwards, push these changes to your fork.
git push
Head to the main repository page https://github.com/ScottSWu/polyhedra and click on the "Pull requests" tab and create a new pull request.
Click "compare accross forks" to show all forks of the project. In the "compare" tab, change it from "compare: master" to your fork. Then hit "Create pull request", fill out the information and submit.
If you need to make additional edits after sending the pull request, make changes directly to your local files, commit, fetch rebase and push them as normal. They will update automatically on the pull request online.
<edit files>
make test
git add -A
git commit -m "message"
git fetch upstream
git rebase upstream/master
<resolve conflicts>
git push
Merge conflicts might look daunting at first, but it mostly ends up being "which version do you want to use?". During the conflict, git will provide both versions in the file itself.
After resolving a conflict, continue the rebase until it finishes.
git add -A
git rebase --continue
Finally push again to the branch.