Kelick Tech Hub

Build, learn & keep up — tech, Linux & sports news included.

C++ Simple Voting System Project

Intermediate•1–2 days•std::map, validation, data integrity

Register voters, cast one ballot each, and tally a tamper-resistant result.

Share on X

What you will build

An election in miniature: candidates are registered, voters authenticate, each voter gets exactly one ballot, and results tally at the end. The interesting problems are integrity ones — preventing double voting and tying every ballot to a verified voter.

What you will learn

Feature checklist

Starter code

#include <iostream>
#include <map>
#include <set>
#include <string>

class Election {
    std::map<std::string, int> tally_;   // candidate -> votes
    std::set<std::string> hasVoted_;
public:
    void addCandidate(const std::string& name) { tally_[name] = 0; }

    bool castVote(const std::string& voterId, const std::string& cand) {
        if (!tally_.count(cand)) return false;          // unknown candidate
        if (hasVoted_.count(voterId)) return false;    // already voted
        hasVoted_.insert(voterId);
        ++tally_[cand];
        return true;
    }

    void results() const {
        int total = 0;
        for (auto& [name, n] : tally_) total += n;
        std::string winner; int best = -1;
        for (auto& [name, n] : tally_) {
            double pct = total ? 100.0 * n / total : 0;
            std::cout << name << ": " << n << " votes (" << pct << "%)\n";
            if (n > best) { best = n; winner = name; }
        }
        std::cout << "Winner: " << winner << "\n";
    }
};

Full walkthrough

Step 1: Model the election in one class

class Election owns everything: a std::map<std::string, int> tally (candidate name → votes) and a std::set<std::string> registered voter IDs plus a set of who has already voted. One class holding candidates AND voters is right at this scale — and the sets are the integrity mechanism, as you will see.

Step 2: addCandidate() with duplicate protection

Admin mode adds candidates into the tally map with 0 votes. Adding the same name twice must not reset an existing count — check count() first, or use emplace which refuses to overwrite. A candidate added mid-election silently zeroing their votes is the kind of bug that ends democracies and demo days.

Step 3: Register voters with unique IDs

Registration inserts the voter's ID into the registered set; insert() returns a pair whose .second tells you whether it was actually new. Duplicate registration is refused with a message. The set does the uniqueness work — no manual scanning.

Step 4: castVote(): the three-gate function

Gate 1: is this ID registered? Gate 2: has this ID already voted (membership in the voted set)? Gate 3: does the chosen candidate exist? Only then tally[candidate]++ and insert the ID into voted. The ORDER of the gates is the audit story: each refusal message names the exact rule that fired.

bool Election::castVote(id, candidate) {
    if (!registered.count(id))  return refuse("not registered");
    if (voted.count(id))        return refuse("already voted");
    if (!tally.count(candidate)) return refuse("no such candidate");
    tally[candidate]++;
    voted.insert(id);
    return true;
}

Step 5: Report the tally with percentages

Total the votes, then print each candidate with count and 100.0 * votes / total percent (guard total == 0 before any voting). Using a double literal 100.0 avoids the integer-division trap from the quiz project. Sort the printout by votes descending — copy the map into a vector of pairs and sort it — so the leader is always on top.

Step 6: Announce the winner, including ties

Find the maximum vote count, collect ALL candidates holding it, and if there is more than one, announce a tie by name. 'First max wins' code that ignores ties will happily crown one of two equal candidates; collecting all maxima is three extra lines and the only honest version.

Step 7: Persist results and registrations

Save candidates, tallies, and both ID sets to a file so an election survives a restart — a results file the checklist demands, and the voted set must be saved too, or a restart re-opens voting to everyone (the digital equivalent of washing off the ink mark).

Common mistakes

Compile and run

g++ -std=c++17 -o voting voting.cpp

Sample run

$ ./voting
Mode: (A)dmin or (V)oter or (R)esults?
> A
Add candidate:
> Ada
Add candidate:
> Bola
Mode: (A)dmin or (V)oter or (R)esults?
> V
Your voter ID:
> V001
Candidates: 1) Ada  2) Bola — your choice:
> 1
Vote recorded for Ada. Thank you!
> V
Your voter ID:
> V001
Refused: voter V001 has already voted.
> R
Ada:  3 votes (60.0%)
Bola: 2 votes (40.0%)
Winner: Ada

Try it in your browser

No browser demo is included for this project. Build the C++ version below — that is the real program.

Related Intermediate projects

← All 60 projects · Classic site (Learn & Sandbox)

Download Fake GPS