Введение в программирование

C++: методы-члены класса, дружественные классы и члены класса

Разбить на страницы
Показывать лекцию целиком

Методы-члены класса

В терминологии объектно-ориентированного программирования функции также называются методами или методами - членами класса, для того чтобы подчеркнуть, что конкретная функция является членом некоторого класса.

По стандарту ANSI C, используемому компилятором Visual C++, любая используемая в модуле компиляции функция должна иметь прототип, включающий в себя тип функции, имя функции и список параметров с их типами. Прототип - это некоторое предварительное описание функции, заканчивающееся символом ;.

Прототип функции должен быть вставлен во все модули компиляции, использующие функцию. Для небольших программ прототип функции обычно записывается в модуль компиляции. Для программ, создаваемых средствами Visual C++, и программ, состоящих из нескольких модулей, прототип функции указывается в заголовочном файле. Объявление функции должно однозначно соответствовать ее прототипу и может находиться в любом модуле компиляции (для которого доступен прототип функции).

Прототип метода, являющегося членом некоторого класса, записывается в заголовочном файле, содержащем объявление класса в теле этого класса.

Метод - член класса может иметь следующие модификаторы доступа:

  • public - общедоступный метод;
  • protected - метод, доступный только для членов и объектов данного класса и наследуемых классов (наследуемых с модификаторами доступа public или protected );
  • private - защищенный метод, доступный только внутри класса.
  • Прототип метода может иметь следующее формальное описание:

    модификатор_доступа тип_метода имя_метода
        (список_параметров);

    Объявление метода может иметь следующее формальное описание:

    модификатор_доступа тип_метода имя_метода
        (список_параметров)
        { тело_метода }

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

    Указатели типа void могут использоваться для объявления параметров метода в том случае, если тип этих параметров на момент компиляции неизвестен.

    Например:

    void Fx(void *pV); //Прототип метода
    ...
    piVar=new int;
    pfVar=new float;
    Fx(piVar);        // Вызов метода для 
                    // параметра типа int
    Fx(pfVar);        // Вызов метода для 
                    // параметра типа float
    ...
    // Реализация метода
    void Fx(void *pV) {*pV=12345;}

    Метод, возвращающий указатель, записывается следующим образом:

    тип *имя_метода(список_параметров).

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

    Язык C++ допускает передачу параметров по значению и по ссылке или указателю. Параметры, передаваемые по значению, при выполнении программы заносятся в стек, и для больших размеров структур или массивов может возникнуть ситуация переполнения стека. Параметры, передаваемые как ссылки или указатели, не копируются в стек.

    Изменение значений самих параметров происходит только для параметров, переданных по ссылке или указателю. При передаче параметра по значению метод изменяет не сам параметр, а его копию.

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

    Язык C++ разрешает рекурсивный вызов методов.

    В методах класса можно использовать ключевое слово this, являющееся указателем на объект данного класса. Это ключевое слово нельзя использовать вне метода члена класса.

    Создание метода-члена класса

    Для того чтобы в среде Visual Studio .NET добавить в класс новый метод - член класса, следует в окне просмотра классов Class View выделить секцию с именем класса и выполнить команду контекстного меню Add|Add Function, а затем в диалоге - мастере построения метода ввести имя метода, его тип, а также определить список параметров.

    При добавлении метода - члена класса в файл реализации класса автоматически добавляется код реализации нового метода, а в заголовочный файл - объявление этого метода.

    Методы с переменным числом параметров

    Метод может иметь переменное число параметров: это указывается в конце списка параметров символом многоточия ... . Методы с переменным числом параметров должны иметь как минимум один описанный формальный параметр.

    Для применения переменного числа параметров можно использовать:

  • макрос va_start(указатель_списка_параметров,последний_параметр) - при инициализации указателя и установке его на начало переменного списка параметров;
  • макрос va_arg(указатель_списка_параметров,i) - при выборе параметра и продвижении указателя в соответствии с его типом на следующий параметр;
  • макрос va_end((указатель_списка_параметров) - при установке указателя на список параметров, равный null, после извлечения значений всех параметров;
  • тип va_list - для создания указателя на список параметров.
  • Например:

    #include <stdio.h>   
        // Библиотека, содержащая тип va_list
    #include <varargs.h>
    #include <iostream>
    int Fx ( int i1, ... ); 
        // Прототип Функции с переменным 
        // числом параметров
    void main( void )
    {   // Вызов функции Fx с различным 
        // числом параметров
    std::cout<< Fx ( 100, 200) );
    std::cout<< Fx ( 5 ) );
    std::cout<< Fx ( -1,-3,45 ) );
    }
    int Fx ( int i1, ... )  
        // Реализация функции с переменным 
        // числом параметров
    {  int sumx,i;
       sumx = 0, i = i1;  
       va_list list1;        
           // Список параметров
       va_start(list1, i1 ); 
           // Инициализация списка параметров
       while( i != -1 )   {
          sumx += i;
          i = va_arg(list1, int);
          //Извлечение следующего параметра
       }
       va_end(list1);      
       return( sumx );
    }

    Указатели на методы-члены класса и на функции

    Указатели на методы и на функции могут быть использованы для передачи метода в качестве параметра другому методу.

    Объявление указателя на метод может иметь следующее формальное описание:

    тип_метода (имя_класса::*имя_метода_указателя)
        (список параметров);
    тип_функции (*имя_ функции_указателя)
        (список параметров);

    Инициализация указателя может иметь следующее формальное описание:

    тип_метода имя_класса::*имя_метода_указателя
        (список параметров)=
        имя_класса::имя_любого_метода;
    тип_функции (*имя_ функции_указателя)
        (список параметров)= имя_функции;

    Вызов метода, объявленного как указатель на метод, может быть выполнен следующим образом:

    (имя_объекта->*имя_ метода_указателя)
        (список параметров);
    (*имя_ функции_указателя)(список параметров);

    Для функций, но не для методов - членов класса, разрешена другая форма вызова метода:

    имя_ функции_указателя(список параметров);
    (имя_ функции_указателя)(список параметров);

    Объявление функции, имеющей в качестве параметра указатель на метод, может иметь следующее формальное описание:

    тип_метода имя_метода (тип_метода_указателя
        (*имя_метода_указателя)
    	(список параметров));

    Вызов метода, использующего в качестве параметра указатель на метод, может иметь следующее формальное описание:

    имя_метода(имя_объекта->*имя_метода_указателя);
    имя_функции(имя_функции_указателя);

    Разрешается создавать массив указателей на функции.

    При использовании указателей на функцию можно не употреблять операцию разыменования или операцию получения адреса.

    Например:

    class a1
    {
    public:
        a1(void);
        ~a1(void);
        int Fx1(int i1);
        int Fx2(int i2);
    };
    a1::a1(void){}
    a1::~a1(void){}
    int a1::Fx1(int i1){    return 1;}
    int a1::Fx2(int i2){    return 2;}
    
    int (*Fy_pointer)();  
        // Объявление указателя на функцию
    int Fy ();
    int _main(int argc, char* argv[])
    {  
         a1* a1Object = new a1();
     int (a1::*Fx_pointer)(int)=a1::Fx2;  
        // Объявление и инициализация указателя
        // на метод - член класса
        int i;
        i=(a1Object->*Fx_pointer)(1);  
        // Вызов по указателю на метод
       std::cout<<i;
       int (*Fy_pointer)()=Fy;          
       // Объявление и инициализация указателя
       // на функцию
       std::cout<<(Fy_pointer)();   
       std::cout<<(*Fy_pointer)();  
       // Вызов по указателю на 
       // функцию (две формы)
        return 0;
    }
    int Fy ()  {return 5;}

    Встроенные функции

    Встроенные функции указываются оператором inline. Применение встроенных функций может несколько сократить время выполнения программы, так как компилятор встраивает код такой функции в том месте программы, где указан ее вызов.

    Например:

    inline void Fx(void) { 
        std::cout<<"Функция Fx"<<std::endl;}
    ...
    Fx(void); 
        // Этот код  будет заменен компилятором
        // на код встроенной функции

    Перегрузка функций и методов

    Язык C++ позволяет выполнять перегрузку функций и методов - членов класса, то есть вызывать функцию (метод) с тем же именем, но с различными типами фактических параметров. Для создания перегружаемой функции следует указать отдельный прототип и сделать отдельное объявление для каждого списка параметров. Если функции различаются только типом и имеют совпадающие списки параметров, то для таких функций перегрузка не допускается.

    Для определения вызываемой перегружаемой функции учитываются только списки параметров, а тип возвращаемого значения не учитывается. При этом для соответствия списка параметров вызываемой функции может применяться преобразование типов и соответствие по многоточию (соответствие по многоточию?) для функций с переменным числом параметров.

    Дружественные члены класса

    Дружественные члены класса (методы) позволяют получить доступ к защищенным модификатором private членам класса из методов других классов. Методы и классы, объявляемые дружественными, иногда также называются друзьями класса.

    Если метод класса A внутри тела класса B объявляется с модификатором friend, что указывает на то, что он является другом класса, то из него разрешен доступ ко всем членам класса B.

    Например:

    class A { public: int Fx();}
    class B { public: friend int A::Fx();
        private:
    }

    Дружественные классы

    Объявление дружественного класса позволяет всем его методам получить доступ ко всем переменным и методам другого класса.

    Например:

    class A {public: int Fx();}
    class B {public:
        friend class A;
        private:
            }

    Дружественный класс или член класса будет доступен только в том случае, если он был объявлен в области видимости самого класса или ранее во внешней области видимости, внутри которой располагается область видимости, содержащая объявление класса с объявлениями друзей класса.

    Например:

    class A {public: 
        // Класс расположен во внешней 
        // области видимости
        int Fx1();
            }
    namespace classB {
        class B {public:
            friend class A;
            friend class C;
            private:
        }
        class C { public:
        // Класс расположен в том же 
         // пространстве имен
            int Fx2();  
        }
    }

    Дружественные классы не наследуются, и их дружественность не является транзитивной.

    Например:

    class A {int Fx();}
    class B {friend class A;}
    class C {friend class B;} 
        // Класс А не является 
        // дружественным классу C
    class D : public B {}  
        // Класс А не является 
        // дружественным классу D
    Страницы:

    Методы-члены класса

    В терминологии объектно-ориентированного программирования функции также называются методами или методами - членами класса, для того чтобы подчеркнуть, что конкретная функция является членом некоторого класса.

    По стандарту ANSI C, используемому компилятором Visual C++, любая используемая в модуле компиляции функция должна иметь прототип, включающий в себя тип функции, имя функции и список параметров с их типами. Прототип - это некоторое предварительное описание функции, заканчивающееся символом ;.

    Прототип функции должен быть вставлен во все модули компиляции, использующие функцию. Для небольших программ прототип функции обычно записывается в модуль компиляции. Для программ, создаваемых средствами Visual C++, и программ, состоящих из нескольких модулей, прототип функции указывается в заголовочном файле. Объявление функции должно однозначно соответствовать ее прототипу и может находиться в любом модуле компиляции (для которого доступен прототип функции).

    Прототип метода, являющегося членом некоторого класса, записывается в заголовочном файле, содержащем объявление класса в теле этого класса.

    Метод - член класса может иметь следующие модификаторы доступа:

  • public - общедоступный метод;
  • protected - метод, доступный только для членов и объектов данного класса и наследуемых классов (наследуемых с модификаторами доступа public или protected );
  • private - защищенный метод, доступный только внутри класса.
  • Прототип метода может иметь следующее формальное описание:

    модификатор_доступа тип_метода имя_метода
        (список_параметров);

    Объявление метода может иметь следующее формальное описание:

    модификатор_доступа тип_метода имя_метода
        (список_параметров)
        { тело_метода }

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

    Указатели типа void могут использоваться для объявления параметров метода в том случае, если тип этих параметров на момент компиляции неизвестен.

    Например:

    void Fx(void *pV); //Прототип метода
    ...
    piVar=new int;
    pfVar=new float;
    Fx(piVar);        // Вызов метода для 
                    // параметра типа int
    Fx(pfVar);        // Вызов метода для 
                    // параметра типа float
    ...
    // Реализация метода
    void Fx(void *pV) {*pV=12345;}

    Метод, возвращающий указатель, записывается следующим образом:

    тип *имя_метода(список_параметров).

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

    Язык C++ допускает передачу параметров по значению и по ссылке или указателю. Параметры, передаваемые по значению, при выполнении программы заносятся в стек, и для больших размеров структур или массивов может возникнуть ситуация переполнения стека. Параметры, передаваемые как ссылки или указатели, не копируются в стек.

    Изменение значений самих параметров происходит только для параметров, переданных по ссылке или указателю. При передаче параметра по значению метод изменяет не сам параметр, а его копию.

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

    Язык C++ разрешает рекурсивный вызов методов.

    В методах класса можно использовать ключевое слово this, являющееся указателем на объект данного класса. Это ключевое слово нельзя использовать вне метода члена класса.

    Создание метода-члена класса

    Для того чтобы в среде Visual Studio .NET добавить в класс новый метод - член класса, следует в окне просмотра классов Class View выделить секцию с именем класса и выполнить команду контекстного меню Add|Add Function, а затем в диалоге - мастере построения метода ввести имя метода, его тип, а также определить список параметров.

    При добавлении метода - члена класса в файл реализации класса автоматически добавляется код реализации нового метода, а в заголовочный файл - объявление этого метода.

    Методы с переменным числом параметров

    Метод может иметь переменное число параметров: это указывается в конце списка параметров символом многоточия ... . Методы с переменным числом параметров должны иметь как минимум один описанный формальный параметр.

    Для применения переменного числа параметров можно использовать:

  • макрос va_start(указатель_списка_параметров,последний_параметр) - при инициализации указателя и установке его на начало переменного списка параметров;
  • макрос va_arg(указатель_списка_параметров,i) - при выборе параметра и продвижении указателя в соответствии с его типом на следующий параметр;
  • макрос va_end((указатель_списка_параметров) - при установке указателя на список параметров, равный null, после извлечения значений всех параметров;
  • тип va_list - для создания указателя на список параметров.
  • Например:

    #include <stdio.h>   
        // Библиотека, содержащая тип va_list
    #include <varargs.h>
    #include <iostream>
    int Fx ( int i1, ... ); 
        // Прототип Функции с переменным 
        // числом параметров
    void main( void )
    {   // Вызов функции Fx с различным 
        // числом параметров
    std::cout<< Fx ( 100, 200) );
    std::cout<< Fx ( 5 ) );
    std::cout<< Fx ( -1,-3,45 ) );
    }
    int Fx ( int i1, ... )  
        // Реализация функции с переменным 
        // числом параметров
    {  int sumx,i;
       sumx = 0, i = i1;  
       va_list list1;        
           // Список параметров
       va_start(list1, i1 ); 
           // Инициализация списка параметров
       while( i != -1 )   {
          sumx += i;
          i = va_arg(list1, int);
          //Извлечение следующего параметра
       }
       va_end(list1);      
       return( sumx );
    }

    Указатели на методы-члены класса и на функции

    Указатели на методы и на функции могут быть использованы для передачи метода в качестве параметра другому методу.

    Объявление указателя на метод может иметь следующее формальное описание:

    тип_метода (имя_класса::*имя_метода_указателя)
        (список параметров);
    тип_функции (*имя_ функции_указателя)
        (список параметров);

    Инициализация указателя может иметь следующее формальное описание:

    тип_метода имя_класса::*имя_метода_указателя
        (список параметров)=
        имя_класса::имя_любого_метода;
    тип_функции (*имя_ функции_указателя)
        (список параметров)= имя_функции;

    Вызов метода, объявленного как указатель на метод, может быть выполнен следующим образом:

    (имя_объекта->*имя_ метода_указателя)
        (список параметров);
    (*имя_ функции_указателя)(список параметров);

    Для функций, но не для методов - членов класса, разрешена другая форма вызова метода:

    имя_ функции_указателя(список параметров);
    (имя_ функции_указателя)(список параметров);

    Объявление функции, имеющей в качестве параметра указатель на метод, может иметь следующее формальное описание:

    тип_метода имя_метода (тип_метода_указателя
        (*имя_метода_указателя)
    	(список параметров));

    Вызов метода, использующего в качестве параметра указатель на метод, может иметь следующее формальное описание:

    имя_метода(имя_объекта->*имя_метода_указателя);
    имя_функции(имя_функции_указателя);

    Разрешается создавать массив указателей на функции.

    При использовании указателей на функцию можно не употреблять операцию разыменования или операцию получения адреса.

    Например:

    class a1
    {
    public:
        a1(void);
        ~a1(void);
        int Fx1(int i1);
        int Fx2(int i2);
    };
    a1::a1(void){}
    a1::~a1(void){}
    int a1::Fx1(int i1){    return 1;}
    int a1::Fx2(int i2){    return 2;}
    
    int (*Fy_pointer)();  
        // Объявление указателя на функцию
    int Fy ();
    int _main(int argc, char* argv[])
    {  
         a1* a1Object = new a1();
     int (a1::*Fx_pointer)(int)=a1::Fx2;  
        // Объявление и инициализация указателя
        // на метод - член класса
        int i;
        i=(a1Object->*Fx_pointer)(1);  
        // Вызов по указателю на метод
       std::cout<<i;
       int (*Fy_pointer)()=Fy;          
       // Объявление и инициализация указателя
       // на функцию
       std::cout<<(Fy_pointer)();   
       std::cout<<(*Fy_pointer)();  
       // Вызов по указателю на 
       // функцию (две формы)
        return 0;
    }
    int Fy ()  {return 5;}

    Встроенные функции

    Встроенные функции указываются оператором inline. Применение встроенных функций может несколько сократить время выполнения программы, так как компилятор встраивает код такой функции в том месте программы, где указан ее вызов.

    Например:

    inline void Fx(void) { 
        std::cout<<"Функция Fx"<<std::endl;}
    ...
    Fx(void); 
        // Этот код  будет заменен компилятором
        // на код встроенной функции

    Перегрузка функций и методов

    Язык C++ позволяет выполнять перегрузку функций и методов - членов класса, то есть вызывать функцию (метод) с тем же именем, но с различными типами фактических параметров. Для создания перегружаемой функции следует указать отдельный прототип и сделать отдельное объявление для каждого списка параметров. Если функции различаются только типом и имеют совпадающие списки параметров, то для таких функций перегрузка не допускается.

    Для определения вызываемой перегружаемой функции учитываются только списки параметров, а тип возвращаемого значения не учитывается. При этом для соответствия списка параметров вызываемой функции может применяться преобразование типов и соответствие по многоточию (соответствие по многоточию?) для функций с переменным числом параметров.

    Дружественные члены класса

    Дружественные члены класса (методы) позволяют получить доступ к защищенным модификатором private членам класса из методов других классов. Методы и классы, объявляемые дружественными, иногда также называются друзьями класса.

    Если метод класса A внутри тела класса B объявляется с модификатором friend, что указывает на то, что он является другом класса, то из него разрешен доступ ко всем членам класса B.

    Например:

    class A { public: int Fx();}
    class B { public: friend int A::Fx();
        private:
    }

    Дружественные классы

    Объявление дружественного класса позволяет всем его методам получить доступ ко всем переменным и методам другого класса.

    Например:

    class A {public: int Fx();}
    class B {public:
        friend class A;
        private:
            }

    Дружественный класс или член класса будет доступен только в том случае, если он был объявлен в области видимости самого класса или ранее во внешней области видимости, внутри которой располагается область видимости, содержащая объявление класса с объявлениями друзей класса.

    Например:

    class A {public: 
        // Класс расположен во внешней 
        // области видимости
        int Fx1();
            }
    namespace classB {
        class B {public:
            friend class A;
            friend class C;
            private:
        }
        class C { public:
        // Класс расположен в том же 
         // пространстве имен
            int Fx2();  
        }
    }

    Дружественные классы не наследуются, и их дружественность не является транзитивной.

    Например:

    class A {int Fx();}
    class B {friend class A;}
    class C {friend class B;} 
        // Класс А не является 
        // дружественным классу C
    class D : public B {}  
        // Класс А не является 
        // дружественным классу D
    Вернуться к учебному плану