НЕКОТОРЫЕ МОМЕНТЫ АНАЛИЗА И СТРУКТУРНОГО ПРЕДСТАВЛЕНИЯ С++ ПРОГРАММ А.В. Яновский Томский государственный университет систем управления и радиоэлектроники, г. Томск Статья «Некоторые моменты анализа и структурного представления С++ программ» посвящена проблемам изучения объектно-ориентированных языков программирования, таких как С++ и структурно-графическому их представлению. SOME POINTS OF THE ANALYSIS AND STRUCTURAL PRESENTATION C++ PROGRAMS А.V. Janovskij This article “Some points ot the analysis and structural presentation C++ programs” is about scientifical problems of study and structural presentation of programs creating on the C++ and other object programming languages. Практика показывает, что изучение студентами объектно-ориентированных языков программирования таких, как С++, например, сопряжено с рядом трудностей. Овладение устойчивыми навыками программирования на С++ невозможно без овладения в той или иной степени языком программирования Си. Язык Си является базисом, над которым надстраивался в свое время С++. Но если студент, имеющий устойчивые стереотипы программирования на Си, приступит к освоению С++, то он сталкнется с большой проблемой. Надо помнить, что Си является языком функций, в то время как С++ является языком классов или, другими словами, объектов. Следовательно, концептуальный стержень программы, написанной на С++ будет существенно отличаться от концептуального стержня программы, написанной на Си. Если Сипрограмма строится вокруг главной функции main(), то программа, написанная на С++ будет иметь совершенно отличное представление, основанное на классах и ничего общего с концептуальной линией языка Си иметь не будет. Помочь студенту разобраться, в новой для него объектно-ориентированной парадигме призвано структурно-графическое представление С++ программ. Структурно-графическое представление С++ программ реализуется с помощью разного рода анализаторов, помогающих представить графически структуру программы, и тем самым облегчить ее анализ. При разработке программных продуктов с элементами анализа и графического представления кодов, написанных на С++, отправной точкой может служить то, что С++ изначально замышлялся как язык объектно1 ориентированного программирования, сочетающий программную «мощь» своего предшественника языка Си и достоинства объектно-ориентированного подхода. Объектно-ориентированное программирование позволяет программисту объединять данные и обрабатывающий их программный код в один блок. В С++ объекты реализуются с помощью классов, которые позволяют программисту определять новые типы данных, так называемые пользовательские типы. Графически класс представляется в форме дерева (Рис. 1). Рис. 1. Древовидное представление С++ класса, сгенерированное анализатором С++ программ С++ позволяет создавать пользовательские типы данных не только внутри других пользовательских типов, но и внутри функций, внутри операторов: class a { struct b { union a{ } ; }; }; main ( ) { class a{ } ; for( int a = 0 ; a < 10 ; a++ ) { 2 class a { int a; }; } } Данная программа пройдет С++ компилятор и предел вложенности объектов наступит только тогда, когда во вложенный оператор for class a мы попытаемся поместить еще один пользовательский тип. К понятию класса, пользовательского типа вплотную примыкает понятие общего интерфейса [4]. Это подразумевает использование общей и частной видимости членов класса, что дает возможность скрыть члены класса от функций, не входящих в этот класс. В классе могут быть и общие, и частные члены. Общие члены класса определяют то, как функции, не являющиеся членами этого класса, могут использовать данный класс. Эти члены класса называются общим интерфейсом класса. Хорошо разработанный интерфейс обычно включает в себя функциичлены, которые выполняют следующее: — Инициализируют переменную типа данного класса. Конструкторы всегда имеют тип public; — Освобождают память, используемую переменной класса. Деструкторы всегда имеют тип public; — Производят первоначальную установку значений частных переменных — членов класса; — Вычисляют значения частных переменных — членов класса; — Выполняют реальную работу объекта. Например: class Shape { public: Shape( float Aside, float Bside, float Cside ); ~Shape( ); float volume( ); void SetA( float newA ); void SetB( float newB ); void SetC( float newC ); 3 float GetA( ); float GetB( ); float GetC( ); private: float a, b, c; float square( ); }; В этом классе девять функций образуют общий интерфейс. Функции Shape и ~Shape являются конструктором и деструктором класса. Следующая функция — это volume выполняет реальную работу по вычислению объема прямоугольного параллелепипеда, ту работу, для которой данный класс и был разработан. И, наконец, шесть функций Get… и Set… позволяют функциям, не являющимся членами данного класса, управлять данными-членами класса (т.е. отыскивать и изменять значения частных переменных). Описав общий интерфейс с этими функциями доступа к данным вместо разрешения прямого доступа к данным-членам, программа класса может изменить способ хранения данных-членов, не влияя на программы, в которых этот класс используется. Это и является основной целью скрытия данных и надлежащего описания общего интерфейса класса. Другой парадигмой объектно-ориентированного программирования, которую необходимо учитывать при анализе С++ программ, является наследование. Механизм наследования предоставляет возможность многократного использования объекта после корректировки его там, где необходимо. С++ дает возможность описать базовые классы (родители) и производные классы (потомки). Производные классы наследуют все общие данные члены и общие функции члены базового класса. Это делает их частью общего интерфейса. Важным моментом при анализе и дальнейшем графическом представлении С++ программы является то, что производный класс в состоянии породить следующий производный класс (Рис. 2). Базовый класс Производный класс Производный класс Производный класс Производный класс 4 Рис. 2. Иерархия классов в С++ При создании разного рода анализаторов С++ программ, призванных облегчить обучение объектно-ориентированным языкам программирования, помимо учета основных парадигм объектно-ориентированного программирования — классов, их видимости, наследования [5] при анализе C++ программ необходимо четко представлять структуру самой программы [3]. Практически любая программа, написанная на C++, начинается с подключения заголовочных файлов посредством включающей директивы препроцессора include [4]. Эти файлы с расширением .h содержат тексты на языке C++. Внутри заголовочного файла может содержаться вызов другого файла с расширением .h и т. д. (рис. 3) Заголовочный файл Заголовочный файл Заголовочный файл Рис. 3. Структура последовательных вызовов заголовочных файлов в C++. В отличие от языка программирования Паскаль [2], например, в C++ отсутствует понятие процедуры. Все подпрограммы являются функциями во главе с основной функцией main. Без main C++ программа не пройдет компилятор. Напротив, в Паскале наличие главной функции необязательно. Минимальная программа на Паскале выглядит begin end., в то время как аналогичная программа на C++ имеет вид: main(){}. В отличие от Паскаля (рис. 4) С++ не предусматривает наличие одной подпрограммы внутри другой. Иерархия подпрограмм (функций) строго определена – они следуют строго друг за другом (рис. 5). Program test; Var i, k: Integer; Procedure Proc; Function F1: Real; Begin End; Function F2: Real; Begin End; Begin End; 5 Function One: Real; Begin End; Function Two: Real; Begin End; Procedure Proc2; Function Fun1: Real; Begin End; Function Fun2: Real; Begin End; Begin End; Begin End; Рис. 4. Структура подпрограмм, заданных на языке Паскаль, и отображающее ее дерево процедур и функций. 6 Рис. 5. Дерево функций в языке программирования C++. Вместе с тем, как и в языке программирования Паскаль, управляющие операторы C++ могут содержать один или более других управляющих операторов (рис. 6). Рис. 6. Дерево операторов в C++. 7 Поэтому структура программы представляет собой дерево функций, к каждой ветви которого привязано дерево структурных операторов соответсвующей функции. Но и здесь есть нюанс. C++ предполагает самое широкое использование локальных переменных. Их можно задавать даже в операторе цикла for: for( int i = 0 ; i < n ; i++ ); При структурно-графическом отображении текста C++ программы возникает необходимость создания «разорванного» дерева данных, то есть дерева данных, фрагменты которого будут располагаться не только внутри классов и функций, но и внутри операторов. Литература 1. Керниган Б., Ритчи Д. Язык программирования Си. — М.: ФИС, 1992. — 204 с. 2. Коффман Э. Б. Турбо Паскаль. — М.: Вильямс, 2002. — 892 с. 3. Погребной В. К., Демин А. Ю., Погребной Д. В. Томография и структурно-графическое представление программ. Сб. Математическое и программное обеспечение САПР, вып. 1. — Томск: Изд. ТПУ, 1997. — с. 8–16. 4. Поттс С., Монк Т. С. Borland C++ в примерах. — Минск: Попурри, 1996. — 723 с. 5. Яновский А. В. Особенности анализа и структурно–графического представления С++ программ // Вестник Московского городского педагогического университета. Серия «Информатика и информатизация образования». — М.: МГПУ, 2005. — 2(5). — с. 139–142. 8