Каково использование чистых виртуальных функций в C++?

  1. Подкасты от канал 9
    1. ITConversations

    2. SE-радио
    3. Журнала доктора Dobbs

    21
    задан Kara 28 June 2013 в 23:54
    поделиться

    8 ответов

    Вкратце, это сделать класс абстрактным, чтобы он не мог быть создан, но дочерний класс может переопределить чистые виртуальные методы для формирования конкретного класса. Это хороший способ определить интерфейс на C ++.

    34
    ответ дан 29 November 2019 в 06:29
    поделиться

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

    Пример абстрактного класса:

    class Foo {
    
        // pure virtual, must be implemented by subclasses
        virtual public void myMethod() = 0;
    
        // normal method, will be available to all subclasses,
        // but *can* be overridden
        virtual public void myOtherMethod();
    };
    

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

    Пример интерфейса:

    class Bar {
    
        // all method are pure virtual; subclasses must implement
        // all of them
        virtual public void myMethod() = 0;
    
        virtual public void myOtherMethod() = 0;
    };
    
    7
    ответ дан 29 November 2019 в 06:29
    поделиться

    Это заставляет производный класс определять функцию.

    14
    ответ дан 29 November 2019 в 06:29
    поделиться

    Чистые виртуальные методы в C ++ - это в основном способ определения интерфейсов без необходимости их реализации.

    4
    ответ дан 29 November 2019 в 06:29
    поделиться

    Представьте, что я хочу смоделировать несколько видов фигур, и все они имеют четко определенную область. Я решил, что каждая фигура должна наследовать IShape («I» для интерфейса), а IShape будет включать метод GetArea () :

    class IShape {
        virtual int GetArea();
    };
    

    Теперь проблема : как мне вычислить площадь формы, если эта форма не отменяет GetArea () ? То есть какая реализация по умолчанию является лучшей? Круги используют пи * радиус ^ 2, квадраты используют длину ^ 2, параллелограммы и прямоугольники используют основание * высоту, треугольники используют 1/2 основания * высоту, ромбы, пятиугольники, восьмиугольники и т. Д. Используют другие формулы.

    Итак, я говорю " если вы - фигура, вы должны определить способ вычисления площади, но черт возьми, если я знаю, что это будет "путем определения метода чисто виртуального:

    class IShape {
        virtual int GetArea() = 0;
    };
    
    3
    ответ дан 29 November 2019 в 06:29
    поделиться

    The idea with abstract classes is that you can still have a variable declared with that type (i.e., it is the static type), but the variable actually refers or points to an actual concrete type (the dynamic type).

    When you invoke a method in C++, the compiler needs to make sure that the method would be supported on that object.

    By declaring the pure virtual function, you are putting a "placeholder" that the compiler can use to say "oh... I know that whatever ends up being referred to by this variable will accept that call" because the actual concrete types will implement it. However, you don't have to provide an implementation in the abstract type.

    If you didn't declare anything, then the compiler would have no effective way of guaranteeing that it would be implemented by all subtypes.

    Of course, if you're asking why you would want to make a class abstract, there's a lot of info around on that.

    0
    ответ дан 29 November 2019 в 06:29
    поделиться

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

    Например:

    class IStudent
    {
        public:
        virtual ~IStudent(){};
        virtual std::string getName() = 0;
    };
    
    
    class Student : public IStudent
    {
        public:
        std::string name;
        std::string getName() { return name; };
        void setName(std::string in) { name = in; };
    };
    
    class School
    {
        public:
        void sendStudentToDetention(IStudent *in) {
            cout << "The student sent to detention is: ";
            cout << in->getName() << endl;
        };
    };
    
    int main()
    {
        Student student;
        student.setName("Dave");
    
        School school;
        school.sendStudentToDetention(&student);
    return 0;
    }
    

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

    1
    ответ дан 29 November 2019 в 06:29
    поделиться

    Чтобы добавить к ответу Стивена Судита:

    «Вкратце, это сделать класс абстрактным, чтобы его нельзя было создать, но дочерний класс может переопределить чистые виртуальные методы для формирования конкретного класса. Это хороший способ определить интерфейс на C ++ »

    . Примером этого может быть базовый класс (возможно, Shape), который вы используете для определения ряда функций-членов, которые его производные классы могут использовать, но хотят предотвратить объявление экземпляра Shape и заставить пользователей использовать только производные классы (которые могут быть, Rectangle, Triangle, Pentagon и т.д.)

    RE: Ответ Джеффа выше

    Неабстрактные классы могут содержать виртуальный член функции и будут созданы. Фактически, для перегрузки функций-членов это требуется, поскольку по умолчанию C ++ не определяет тип среды выполнения переменной, но при определении с использованием ключевого слова th virtual он будет.

    Рассмотрим этот код (примечание, аксессоры, мутаторы, конструкторы и т. д. не включены для ясности):

    class Person{
      int age;
    
      public:
        virtual void print(){
          cout << age <<endl;
        }
    }
    
    class Student: public Person{
      int studentID
    
      public:
        void print(){
          cout << age << studentID <<endl;
        }
    }
    

    Теперь при запуске этого кода:

     Person p = new Student();
     p.print();
    

    без виртуальное ключевое слово, будет напечатан только возраст, а не возраст и идентификатор студента, как предполагается для класса Student

    (этот пример основан на очень похожем примере из C ++ для программистов java http: // www.amazon.com/Java-Programmers-Mark-Allen-Weiss/dp/013919424X)

    @Steven Sudit: вы совершенно правы, я забыл включить фактическое наследование, да! Аксессуары и т. Д. Не включены для большей ясности, и теперь я сделал это более очевидным.

    class Person{
      int age;
    
      public:
        virtual void print(){
          cout << age <<endl;
        }
    }
    
    class Student: public Person{
      int studentID
    
      public:
        void print(){
          cout << age << studentID <<endl;
        }
    }
    

    Теперь при запуске этого кода:

     Person p = new Student();
     p.print();
    

    без ключевого слова virtual будет напечатан только возраст, а не возраст и идентификатор студента, как предполагается для класса Student

    (этот пример основан на очень похожем один из C ++ для java-программистов http://www.amazon.com/Java-Programmers-Mark-Allen-Weiss/dp/013919424X )

    @Steven Sudit: вы совершенно правы, я пренебрегал включить фактическое наследование, да! Аксессуары и т. Д. Не включены для большей ясности, и теперь я сделал это более очевидным.

    class Person{
      int age;
    
      public:
        virtual void print(){
          cout << age <<endl;
        }
    }
    
    class Student: public Person{
      int studentID
    
      public:
        void print(){
          cout << age << studentID <<endl;
        }
    }
    

    Теперь при запуске этого кода:

     Person p = new Student();
     p.print();
    

    без ключевого слова virtual будет напечатан только возраст, а не возраст и идентификатор студента, как предполагается для класса Student

    (этот пример основан на очень похожем один из C ++ для java-программистов http://www.amazon.com/Java-Programmers-Mark-Allen-Weiss/dp/013919424X )

    @Steven Sudit: вы совершенно правы, я пренебрегал включить фактическое наследование, да! Аксессуары и т. Д. Не включены для большей ясности, и теперь я сделал это более очевидным. com / Java-Programmers-Mark-Allen-Weiss / dp / 013919424X )

    @Steven Sudit: вы совершенно правы, я не учел фактическое наследование, о! Аксессуары и т. Д. Не включены для большей ясности, и теперь я сделал это более очевидным. com / Java-Programmers-Mark-Allen-Weiss / dp / 013919424X )

    @Steven Sudit: вы совершенно правы, я не учел фактическое наследование, о! Аксессуары и т. Д. Не включены для большей ясности, и теперь я сделал это более очевидным. 3-7-09: все исправлено

    3
    ответ дан 29 November 2019 в 06:29
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: