Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Ада и другие языки _ выявление слабых мест в коде

Автор: -NIK- 25.01.2008 9:03

Здравствуйте.
Получили такое вот задание, немного не привычное - не напписать простенькую программу или типо того, а найти "проблемы" в данном програмном коде. Как я понимаю, нужно посмотреть на код и выявить как ошибки так и не достатки видные с полета профессионального или опытного программиста. Простите, но я кроме парочки претензий к конструкторам да и то не сильно обоснвоанных ничего не увидел. прошу помочь, нужно срочно.#include<iostream>

class Foo
{
public:
Foo(int j) { i=new int[j]; s = j}
~Foo() { delete i; }
private:
int* i;
int s;
};

class Bar: Foo
{
public:
Bar(int j) { i=new char[j]; }
operator>> (Bar b) { for (int k = 0; k < s; k++) { cout << b.i[k] << " "; } }
~Bar() { delete i; }
private:
char* i;
};

int main()
{
int i;
cin>>i;
for(int j=100;j<-100;j--);
{
if(j%3=0)
i+=i++ + ++i;
}

Foo* f=new Foo(i);
Foo* b=new Bar(j);
*f=*b;
delete f;
delete b;
}

Автор: volvo 25.01.2008 14:10

По Стандарту этот код вообще не будет компилироваться:
1) operator >> это функция, и надо указывать ее тип, у тебя этого не сделано (кстати, перегрузка операции ввода для класса, описанная в самом классе, да еще и в которой производится вывод элементов - это очень "сильный" ход...);
2) при инициализации наследника не производится инициализация предка (у предка нет конструктора без параметров)

"Пустые" (ничего не выполняющие) циклы, проблемы с уровнями доступа - обращение к частным членам предка в потомке. У тебя, кстати, вообще не общее, а частное наследование:

class Bar: Foo {

аналогично
class Bar: private Foo {

Так что ты меня извини, но искать недочеты можно в программе, которая хотя бы успешно компилируется, а не в той, которая валится на этапе компиляции. Тут речь идет уже не о "проблемах", а об обычных синтаксических ошибках, выявить которые помогает любой более или менее соответствующий Стандарту компилятор.

Автор: Гость 25.01.2008 16:47

Нет, нет, боюсь вы не совсем правильно меня поняли. Дело в том, что это не моя программа, которую мне сказали исправить. Это такое задание конкретное и предложенное преподавателем - попункто выписать очевидные, и не очень недостатки и недочеты. Т.е. не могли бы Вы как раз вот подобные замечания, но на более доступном уровне. Заранее благодарю...

Автор: volvo 25.01.2008 17:42

Я же говорю:
1) при инициализации Bar сначала должна производиться инициализация Foo, как родительского типа. Явно (ну, к примеру, так:

...
Bar(int j): Foo(j) { ... }
...

) этого не делается, компилятор попытается инициализировать Foo самостоятельно, но вот незадача: у Foo есть 2 конструктора (один описан тобой, второй - неявно созданный компилятором Foo(const Foo &)), и ни один из них не является конструктором без параметров (или хотя бы с параметром по-умолчанию, чтобы его можно было вызвать так: Foo()). В таком случае компилятор просто не знает, что делать.

2) перегрузка operator >>... Это ввод из потока, соответственно, если ты внутри делаешь cout << ..., то что-то неладно в Датском королевстве. Будем надеяться, что речь идет именно о выводе, тогда придется сделать следующее: описать operator << как "друга" класса Bar с первым параметром - потоком в который будет производится вывод, потому что если ты опишешь это внутри класса, то первым параметром при вызове должен будет передаваться именно экземпляр класса, и вызывать так, как это принято:
cout << *b;
ты не сможешь. Вот так будет лучше:

class Bar: Foo
{
...
friend ostream& operator << (ostream &os, const Bar &b) {
// для того чтобы обращаться здесь к s, ее в базовом классе надо сделать
// не частной (private), а защищенной (protected)
for (int k = 0; k < b.s; k++) {
os << b.i[k] << " ";
}
return os;
}
...



Дальше...

3)
for(int j=100;j<-100;--j);
Что здесь делает точка с запятой? Определяет, что есть пустое тело цикла. То есть, никаких полезных действий не будет предпринято. Опять же, переменная j существует только внутри цикла, поэтому в строке
if(j%3=0)
она будет просто недоступна (по крайней мере должна быть, на современном компиляторе). Еще один подвох в этой строке - использование одного знака '=' вместо удвоенного, что порождает еще одну ошибку: нельзя присваивать ничего выражению, его можно только с чем-то сравнивать...

4) строка
i+=i++ + ++i; 
тоже некорректна, почему - читай здесь: http://forum.pascal.net.ru/index.php?s=&showtopic=19365&view=findpost&p=108835

5) ну, и наконец (если даже ты исправишь ошибку с несуществующей переменной j, и подкорректируешь все то, что я написал выше), программа не будет компилироваться. Она застрянет здесь:
Foo* b=new Bar(j);
. Почему - я тебе уже сказал в предыдущем посте: наследование Bar от Foo - частное, поэтому общие (и защищенные тоже) члены частного базового класса становятся в производном классе частными, следовательно приведенная мной строчка некорректна, чтобы это заработало надо сделать общее наследование:
class Bar: public Foo {
...


6) согласно требованиям Стандарта языка С++ программа должна возвращать значение, твоя программа (ну или чья-то там, неважно, вопрос-то задаешь ты) этого не делает...

Это все касается только компиляции программы. Что касается выполнения - то поскольку конструктор копирования генерируется автоматически (если его не предусмотрел программист) - с большой степенью вероятности он не будет делать того, что ты хочешь, следовательно, чтобы программа работала правильно, его лучше написать самому...