Specify, design, and implement a class that can be used in a program that simulates a combination lock. The lock has a circular knob, with the numbers 0 through 39 marked on the edge, and it has a three-number combination, which we’ll call x, y, z. To open the lock, you must turn the knob clockwise at least one entire revolution, stopping with x at the top; then turn the knob counter-clockwise, stopping the second time that y appears at the top; finally turn the knob clockwise again, stopping the next time that z appears at the top. At this point, you may open the lock.
Your lock class should have a constructor that initializes the three-number combination(use 0, 0, 0 for default arguments). Also provide member functions:
( a ) to alter the lock’s combination to a new three-number combination
( b ) to turn the knob in a given direction until a specified number appears at the top
( c ) to close the lock
( d ) to attempt to open the lock
( e ) to inquire about the status of the lock(open or shut)
( f ) to tell you what number is currently at the top
This question is located in p120 of Data Structures and Other Objects Using C++(Fourth Edition).
According to the tips from the question, we should design a class to implement a combination lock. To design a class, class member variables and member functions must be taken into consideration.
These questions are not so difficult. I am aimed at practicing my English writing and review the knowledge of software engineering. Pay more effort to the design and documentation instead of codes.
Complete a class and draw the class diagram.
To indicate the current value of x, y, z respectively, we declare them as private variables.
To indicate whether the user has turned the knob clockwise one revolution and adjust x, y, z in sequence, we declare a bool variable called has_right_operation_sequence. We need to check it when we attempt to open the clock. To support us in checking the value of has_right_operation_sequence, we declare adjust_one_revolution, adjust_x, adjust_y( both of them are bool variables).
Additionally, we need a integrated value called top to indicate the current value of top. To check whether our tuple is matched with the correct key of the combination lock, we are supposed to declare a structure to hold the key.
I think I need these operation below referenced to a-f:
When it comes to the constructor, we have both a default constructor and a overloaded constructor which receives three integrated values as its arguments. They are:
combination_lock();
combination_lock(int, int, int);
( a )
void turn_knob_clockwise_one_revolution();
int alter_x_to_top();
int alter_y_to_top();
int alter_z_to_top();
( b )
void set_top_val(int val);
If the val is less than 0, it will not pass the assertion. If the val is larger than 39, it will be set to the remaining value after being divided. The actual value called α \alpha α is calculated as below.
α = v a l   m o d   40 \alpha = val\,mod\,40 α=valmod40
( c )
void close_lock();
( d )
int attempt_open_lock();
void initialize_key(int, int, int);
( e )
int lock_status();
( f )
int get_top_val();
This diagram is generated by visual studio 2017.
According to the description of the question, I attempt to draw a flow diagram using UML.
// lock.h
#pragma once
struct lock_key {
int i;
int j;
int k;
};
enum lock_status { OPEN, SHUT };
class combination_lock {
public:
combination_lock() {
int x = 0;
int y = 0;
int z = 0;
int top = 0;
};
combination_lock(int m, int n, int p) {
int x = m;
int y = n;
int z = p;
int top = 0;
};
void turn_knob_clockwise_one_revolution();
int alter_x_to_top();
int alter_y_to_top();
int alter_z_to_top();
void set_top_val(int);
void close_lock();
int attempt_open_lock();
int lock_status();
int get_top_val();
void initialize_key(int, int, int);
private:
int x, y, z, top;
bool has_right_operation_sequence = false;
bool adjust_one_revolution = false;
bool adjust_x = false;
bool adjust_y = false;
int status = SHUT;
lock_key key;
};
// lock.cpp
#include "pch.h"
#include "lock.h"
#include
#include
void combination_lock::turn_knob_clockwise_one_revolution()
{
adjust_one_revolution = true;
}
int combination_lock::alter_x_to_top()
{
assert(adjust_one_revolution);
adjust_x = true;
x = top;
return 0;
}
int combination_lock::alter_y_to_top()
{
assert(adjust_one_revolution && adjust_x);
adjust_y = true;
y = top;
return 0;
}
int combination_lock::alter_z_to_top()
{
assert(adjust_one_revolution && adjust_x && adjust_y);
has_right_operation_sequence = true;
z = top;
return 0;
}
void combination_lock::set_top_val(int val)
{
top = val % 40;
}
void combination_lock::close_lock()
{
status = SHUT;
}
int combination_lock::attempt_open_lock()
{
assert(has_right_operation_sequence);
if ((key.i == x) && (key.j == y) && (key.k == z)) {
status = OPEN;
return 0;
}
else {
status = SHUT;
return -1;
}
}
int combination_lock::lock_status()
{
return status;
}
int combination_lock::get_top_val()
{
return top;
}
void combination_lock::initialize_key(int m, int n, int q)
{
key.i = m;
key.j = n;
key.k = q;
}
#include "pch.h"
#include "lock.h"
#include
/*
* incorrect combination of x, y, z
*/
int main()
{
combination_lock a;
a.initialize_key(1, 2, 3);
a.turn_knob_clockwise_one_revolution();
std::cout << "Before operation:\n";
if (a.lock_status() == SHUT) {
std::cout << "It is locked on!\n";
}
else {
std::cout << "It is unlocked!\n";
}
a.set_top_val(1);
a.alter_x_to_top();
a.set_top_val(2);
a.alter_y_to_top();
a.set_top_val(43);
a.alter_z_to_top();
std::cout << "After operation:\n";
if (a.attempt_open_lock() == 0) {
std::cout << "succeeded to open!\n";
}
else {
std::cout << "failed to open!\n";
}
if (a.lock_status() == SHUT) {
std::cout << "It is locked on!\n";
}
else {
std::cout << "It is unlocked!\n";
}
std::cout << "lock it\n";
a.close_lock();
return 0;
}
#include "pch.h"
#include "lock.h"
#include
/*
* incorrect combination of x, y, z
*/
int main()
{
combination_lock a;
a.initialize_key(1, 2, 3);
a.turn_knob_clockwise_one_revolution();
std::cout << "Before operation:\n";
if (a.lock_status() == SHUT) {
std::cout << "It is locked on!\n";
}
else {
std::cout << "It is unlocked!\n";
}
a.set_top_val(1);
a.alter_x_to_top();
a.set_top_val(35);
a.alter_y_to_top();
a.set_top_val(43);
a.alter_z_to_top();
std::cout << "After operation:\n";
if (a.attempt_open_lock() == 0) {
std::cout << "succeeded to open!\n";
}
else {
std::cout << "failed to open!\n";
}
if (a.lock_status() == SHUT) {
std::cout << "It is locked on!\n";
}
else {
std::cout << "It is unlocked!\n";
}
std::cout << "lock it\n";
a.close_lock();
return 0;
}
output(incorrect combination):
#include "pch.h"
#include "lock.h"
#include
/*
* forget to turn knob clockwise one revolution before operating
*/
int main()
{
combination_lock a;
a.initialize_key(1, 2, 3);
std::cout << "Before operation:\n";
if (a.lock_status() == SHUT) {
std::cout << "It is locked on!\n";
}
else {
std::cout << "It is unlocked!\n";
}
a.set_top_val(1);
a.alter_x_to_top();
a.set_top_val(2);
a.alter_y_to_top();
a.set_top_val(43);
a.alter_z_to_top();
std::cout << "After operation:\n";
if (a.attempt_open_lock() == 0) {
std::cout << "succeeded to open!\n";
}
else {
std::cout << "failed to open!\n";
}
if (a.lock_status() == SHUT) {
std::cout << "It is locked on!\n";
}
else {
std::cout << "It is unlocked!\n";
}
std::cout << "lock it\n";
a.close_lock();
return 0;
}
output(wrong operation sequence, an assertion error occurred):
Design is important.
整理自 Data Structures and Other Objects Using C++ ( Fourth Edition ) Michael Main, Walter Savitch.