4.8 KiB
4.8 KiB
Good practise
What can we do better?
class Bar {
public:
void doSth() {
std::cout << "Do sth\n";
}
};
class Foo {
public:
Foo(std::string name) {
name_ = name;
bar_ = new Bar();
}
~Foo() {
delete bar_;
bar_ = nullptr;
}
void printName() {
std::cout << name_ << std::endl;
}
void doSth() {
bar_->doSth();
}
private:
Bar* bar_;
std::string name_;
};
Refactor
class Bar {
public:
// doSth should be cont method because only print sth
void doSth() {
std::cout << "Do sth\n";
}
};
class Foo {
public:
// Get string by const& or use std::move when initialize
Foo(std::string name) {
// Use initialization list, instead assign inside C'tor
name_ = name;
// Avoid usage of new, use unique_ptr and make_unique method
// Class Foo will be hard to test because we can't substitute bar objects!
// Bar should be provided in C'tor -> Dependency injection
bar_ = new Bar();
}
~Foo() {
// Unneccessary, because we should use unique_ptr
delete bar_;
bar_ = nullptr;
}
// Should be const method
void printName() {
// better use '\n' then endline
// If you need to flush stream use flush() method
std::cout << name_ << std::endl;
}
// If there is a risk, that ptr may by empty, we shoudl validate it
void doSth() {
bar_->doSth();
}
private:
Bar* bar_;
std::string name_;
};
What can we do better?
class Screen {
public:
Screen(int height, int width) : height_(height), width_(width) {}
Screen(int size) : height_(size), width_(size) {}
~Screen() {}
void print(const std::vector<int>& numbers) {
int current = 0;
for (int j = 0; j < width_; ++j) {
std::cout << "_";
}
std::cout << '\n';
for (int i = 0; i < height_; ++i) {
std::cout << "|";
for (int j = 0; j < width_; ++j) {
int num_width = std::to_string(numbers[current]).size();
std::cout << numbers[current];
j += num_width;
if (j < width_) {
std::cout << ' ';
}
++current;
}
std::cout << "|\n";
}
for (int j = 0; j < width_; ++j) {
std::cout << "_";
}
std::cout << '\n';
}
private:
Screen() {}
int height_;
int width_;
};
Refactor
class Screen {
public:
// Use alias -> using Height = int
Screen(int height, int width)
: height_(height), width_(width) {}
// User probably not expect square screen when initialize with one value
// C'tor with on argument should be mark as explicit.
Screen(int size)
: height_(size), width_(size) {}
// Not needed here, we also break rule of 5
~Screen() {}
// Should be const method
void print(const std::vector<int>& numbers) {
int current = 0;
// This function repeat twice.
// Should be separate function like print underscore
for (int j = 0; j < width_; ++j) {
// This is not efficient better use std::cout << string(width_, '_') << '\n';
std::cout << "_";
}
std::cout << '\n';
// This is hard to understand. There is already implemented stream mainpulators
// like <iomanip> which allow to use `setw` to describe the width ov vlaue
// or added in c++20 std::format()
for (int i = 0; i < height_; ++i) {
std::cout << "|";
for (int j = 0; j < width_; ++j) {
// should be const
int num_width = std::to_string(numbers[current]).size();
std::cout << numbers[current];
// do sth with `j` which should be handled by for loop
j += num_width;
if (j < width_) {
std::cout << ' ';
}
++current;
}
std::cout << "|\n";
}
// DRY - do not repeat yourself
for (int j = 0; j < width_; ++j) {
std::cout << "_";
}
std::cout << '\n';
}
private:
// By default when we create at least one C'tor, the compiler will not add a default one
Screen() {}
int height_;
int width_;
};