Uploaded by dmitrij.garbuzov.98

Прософт-Системы.Тестовое практическое задание Программист СС++

advertisement
Перечислите все проблемы, которые вы видите в данном коде:
class Foo
{
public:
Foo(int j) { i=new int[j]; }
~Foo() { delete i; } //Виртуальный деструктор класса позволит удалять потомков класса Foo
через их предка
private:
int* i;
};
class Bar: Foo //Наследование с модификатором доступа public позволит использовать поля и методы
класса Foo (см. 23 строку)
{
public:
Bar(int j) { i=new char[j]; } //Необходимо добавить “Foo(j)” в список инициализациии
~Bar() { delete i; }
private:
char* i;
};
void main() //Предпочтительнее использовать int как тип возвращаемого значения функции main
{
Foo* f=new Foo(100);
Foo* b=new Bar(200); (23 строка)
*f=*b;
delete f;
delete b; //После реализации виртуального деструктора нет необходимости в данной инструкции
}
Есть класс CodeGenerator, который умеет генерить код на разных языках.
Предложите рефакторинг с учетом, что количество языков будет расширяться
class CodeGenerator
{
public:
enum Lang {JAVA, C_PLUS_PLUS, PHP};
CodeGenerator(Lang language) { _language=language; }
std::string generateCode()
{
switch(_language) {
case JAVA:
//return generated java code
case C_PLUS_PLUS: //return generated C++ code
case PHP:
//return generated PHP code
}
throw new std::logic_error("Bad language");
}
std::string someCodeRelatedThing() // used in generateCode()
{
switch(_language) {
case JAVA:
//return generated java-related stuff
case C_PLUS_PLUS: //return generated C++-related stuff
case PHP:
//return generated PHP-related stuff
}
throw new std::logic_error("Bad language");
}
private:
Lang _language;
}
_____________________________________________________________________________
class Lang
{
public:
Lang() {};
virtual string returnGeneratedCode(){};
virtual string returnSomething(){};
};
class CPP: public Lang{
public:
string returnGeneratedCode() override {};
string returnSomething() override {} ;
};
class Java: public Lang{
public:
string returnGeneratedCode() override;
};
class CodeGenerator {
public:
CodeGenerator(Lang language) { _language=language; }
std::string generateCode()
{
return _language.returnGeneratedCode();
}
std::string someCodeRelatedThing() // used in generateCode()
{
return _language.returnSomething();
}
private:
Lang _language;
};
Идея реализации заключается в том, что основные принципы ООП (наследование и инкапсуляция, в
частности) позволят избежать лишних инструкций выбора, заменив последние на соответствующие
методы класса-родителя
Все ли хорошо в этом коде?
Файл legacy.c
int values[3]; //Декларацию массива value с помощью ключевого слова extern необходимо производить
здесь, а не ниже
Файл modern.cpp
#define LEGACY_SIZE 3
extern int *values; //Необходимо убрать «extern int *», но добавить размерность массива values[3]
class MyBlah {...}; //Необходимо указать конструктор класса с типом принимаемого аргумента int
values[3]
class Adapter
{
public:
Adapter()
{
for (int i = 0; i < LEGACY_SIZE; ++i)
map_[values[i]] = new MyBlah (values[i]);
}
private:
std::map<int, MyBlah *> map_;
};
Что не так в этом коде? Перечислите, какие недостатки вы видите. Предложите
свой вариант рефакторинга.
#include <stdio.h>
class Feature
{
public:
enum FeatureType {eUnknown, eCircle, eTriangle, eSquare};
Feature() : type(eUnknown), points(0) {
}
~Feature()
{
if (points)
delete points; //Деструктор с условием, которое вызывает подозрения
}
bool isValid()
{
return type != eUnknown;
}
bool read(FILE* file)
{
if (fread(&type, sizeof(FeatureType), 1, file) != sizeof(FeatureType))
return false;
short n = 0;
switch (type) //Использование условного оператора приводит к излишнему повторению кода и
сложности при его изменении
{
case eCircle: n = 3; break; //Не интуитивно понятная переменная n
case eTriangle:
n = 6; break; //Предпочтительнее использовать отдельный метод, общего
класса Shape (напр.), в котором будут поля для координат вершин (в случае с треугольником и
квадратом) и координат центра и длины радиуса для окружности, а так же методы по типу draw и read
case eSquare: n = 8; break;
default: type = eUnknown; return false;
}
points = new double[n];
if (!points)
return false;
return fread(&points, sizeof(double), n, file) == n*sizeof(double);
}
void draw()
{
switch (type)
{
case eCircle: drawCircle(points[0], points[1], points[2]); break;
case eTriangle:
drawPoligon(points, 6); break;
case eSquare: drawPoligon(points, 8); break;
}
}
protected:
void drawCircle(double centerX, double centerY, double radius);
void drawPoligon(double* points, int size);
double* points;
FeatureType type;
};
int main(int argc, char* argv[])
{
Feature feature;
FILE* file = fopen("features.dat", "r");
feature.read(file);
if (!feature.isValid())
return 1;
return 0;
}
Имеем чистый C. Напишите generic функцию линейного поиска в массиве. И приведите пример
использования вашей функции.
int generic(int A[], int key)
{
for (i = 0; i < N; i++)
if (A[i] == key) return i;
return -1;
}
Данная функция может использоваться при поиске символа в последовательности (например, рандомно
сгенерированном массиве переменных типа int)
#include <iostream>
#include <ctime>
using namespace std;
int i, N;
int generic(int A[], int key)
{
for (i = 0; i < N; i++)
if (A[i] == key) return i;
return -1;
}
int main()
{
int key, A[1000];
srand(time(NULL));
cout << "Array Size (max1000): "; cin >> N;
cout << "The desired element: "; cin >> key;
cout << "Source array: ";
for (i = 0; i < N; i++)
{
A[i] = rand() % 10;
cout << A[i] << " ";
}
if (generic(A, key) == -1) cout << "\nElement not found";
else cout << "\nItem Number: " << generic(A, key) + 1;
}
Имеем чистый С. Напишите reusable API для работы со связным списком структур. Структуры могу
быть разного типа, но в одном списке будут структуры одного типа. Приведите пример
использования вашего API.
Затрудняюсь ответить
Download