Наследование (программирование)

Наследование (программирование)

Насле́дование — механизм объектно-ориентированного программирования (наряду с инкапсуляцией, полиморфизмом и абстракцией), позволяющий описать новый класс на основе уже существующего (родительского), при этом свойства и функциональность родительского класса заимствуются новым классом.

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

Содержание

Типы наследования

Простое наследование

Класс, от которого произошло наследование, называется базовым или родительским (англ. base class). Классы, которые произошли от базового, называются потомками, наследниками или производными классами (англ. derived class).

В некоторых языках используются абстрактные классы. Абстрактный класс — это класс, содержащий хотя бы один абстрактный метод, он описан в программе, имеет поля, методы и не может использоваться для непосредственного создания объекта. То есть от абстрактного класса можно только наследовать. Объекты создаются только на основе производных классов, наследованных от абстрактного. Например, абстрактным классом может быть базовый класс «сотрудник вуза», от которого наследуются классы «аспирант», «профессор» и т. д. Так как производные классы имеют общие поля и функции (например, поле «год рождения»), то эти члены класса могут быть описаны в базовом классе. В программе создаются объекты на основе классов «аспирант», «профессор», но нет смысла создавать объект на основе класса «сотрудник вуза».

Множественное наследование

При множественном наследовании у класса может быть более одного предка. В этом случае класс наследует методы всех предков. Достоинства такого подхода в большей гибкости. Множественное наследование реализовано в C++. Из других языков, предоставляющих эту возможность, можно отметить Python и Эйфель. Множественное наследование поддерживается в языке UML.

Множественное наследование — потенциальный источник ошибок, которые могут возникнуть из-за наличия одинаковых имен методов в предках. В языках, которые позиционируются как наследники C++ (Java, C# и др.), от множественного наследования было решено отказаться в пользу интерфейсов. Практически всегда можно обойтись без использования данного механизма. Однако, если такая необходимость все-таки возникла, то, для разрешения конфликтов использования наследованных методов с одинаковыми именами, возможно, например, применить операцию расширения видимости — «::» — для вызова конкретного метода конкретного родителя.

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

Большинство современных объектно-ориентированных языков программирования (C#, Java, Delphi и др.) поддерживают возможность одновременно наследоваться от класса-предка и реализовать методы нескольких интерфейсов одним и тем же классом. Этот механизм позволяет во многом заменить множественное наследование — методы интерфейсов необходимо переопределять явно, что исключает ошибки при наследовании функциональности одинаковых методов различных классов-предков.

Единый базовый класс

В ряде языков программирования все классы явно или неявно наследуются от некого базового класса. Smalltalk был одним из первых языков, в которых использовалась эта концепция. К таким языкам относятся Objective-C (NSObject), Perl (UNIVERSAL), Eiffel (ANY), Java (java.lang.Object), C# (System.Object), Delphi (TObject).

Наследование в языках программирования

Visual Basic

Наследование в Visual Basic:

Class A 'базовый класс
End Class
 
Class B : Inherits A    'наследование от A
End Class
 
Noninheritable Class C     'Класс, который нельзя наследовать (final в Java)
End Class
 
MustInherit Class Z 'Класс, который обязательно наследовать (абстрактный класс)
End Class

C++

Наследование в C++:

class A{    //базовый класс
};
 
class B : public A{    //public наследование
};
 
class C : protected A{    //protected наследование
};
 
class Z : private A{    //private наследование
};

В C++ существует три типа наследования: public, protected, private. Спецификаторы доступа членов базового класса меняются в потомках следующим образом:

ANSI ISO IEC 14882 2003

Если класс объявлен как базовый для другого класса со спецификатором доступа public, тогда public члены базового класса доступны как public члены производного класса, protected члены базового класса доступны как protected члены производного класса.

Если класс объявлен как базовый для другого класса со спецификатором доступа protected, тогда public и protected члены базового класса доступны как protected члены производного класса.

Если класс объявлен как базовый для другого класса со спецификатором доступа private, тогда public и protected члены базового класса доступны как private члены производного класса.

\ANSI ISO IEC 14882 2003

Одним из основных преимуществ public-наследования является то, что указатель на классы-наследники может быть неявно преобразован в указатель на базовый класс, то есть для примера выше можно написать:

A* a = new B();

Эта интересная особенность открывает возможность динамической идентификации типа (RTTI).

Delphi (Object Pascal)

Для использования механизма наследования в Delphi необходимо в объявлении класса справа от слова class указать класс предок:

Предок:

TAncestor = class
private
protected
public
  // Виртуальная процедура
  procedure VirtualProcedure; virtual; abstract; 
  procedure StaticProcedure;
end;

Наследник:

TDescendant = class(TAncestor)
private
protected
public
  // Перекрытие виртуальной процедуры
  procedure VirtualProcedure; override;
  procedure StaticProcedure;
end;

Абсолютно все классы в Delphi являются потомками класса TObject. Если класс-предок не указан, то подразумевается, что новый класс является прямым потомком класса TObject.

Множественное наследование в Delphi частично поддерживается за счёт использования классов-помощников (Сlass Helpers).

Python

Python поддерживает как одиночное, так и множественное наследование. При доступе к атрибуту порядок просмотра производных классов называется порядком разрешения метода (англ. method resolution order)[1].

class Ancestor1(object):   # Предок 1
    def m1(self): pass
class Ancestor2(object):   # Предок 2
    def m1(self): pass
class Descendant(Ancestor1, Ancestor2):   # Наследник
    def m2(self): pass
 
d = Descendant()           # инстанциация
print d.__class__.__mro__  # порядок разрешения метода:
(<class '__main__.Descendant'>, <class '__main__.Ancestor1'>, <class '__main__.Ancestor2'>, <type 'object'>)

С версии Python 2.2 в языке сосуществуют «классические» классы и «новые» классы. Последние являются наследниками object. «Классические» классы будут поддерживаться вплоть до версии 2.6, но удалены из языка в Python версии 3.0.

Множественное наследование применяется в Python, в частности, для введения в основной класс классов-примесей (англ. mix-in).

PHP

Для использования механизма наследования в PHP необходимо в объявлении класса после имени объявляемого класса-наследника указать слово extends и имя класса-предка:

class Descendant extends Ancestor {
}

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

class A {
  function example() {
    echo "Вызван метод A::example().<br />\n";
  }
}
 
class B extends A {
  function example() {
    echo "Вызван метод B::example().<br />\n";
    parent::example();
  }
}

Objective-C

@interface MyNumber : NSObject { 
   int num;
}
- (int) num;
- (void) setNum: (int) theNum;
@end
 
@implementation
- (id) init { 
   self = [super init];
   return self;
}
 
- (int) num {
   return num;
}
 
- (void) setNum: (int) theNum {
   num = theNum;
}
@end

Переопределенные методы не нужно объявлять в интерфейсе.

Java

Пример наследования от одного класса и двух интерфейсов:

        public class A { }
        public interface I1 { }
        public interface I2 { }
        public class B extends A implements I1, I2 { }

Директива final в объявлении класса делает наследование от него невозможным.


C#

Пример наследования от одного класса и двух интерфейсов:

        public class A { }
        public interface I1 { }
        public interface I2 { }
        public class B : A, I1, I2 { }

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

        public class A<T>
        { }
        public class B : A<int>
        { }
        public class B2<T> : A<T>
        { }

Допустимо также наследование вложенных классов от классов, их содержащих:

    class A
    {
        public class B : A { }
    }

Директива sealed в объявлении класса делает наследование от него невозможным.[2]

Ruby

class Parent
 
  def public_method
    "Public method"
  end
 
  private
 
    def private_method
      "Private method"
    end
 
end
 
class Children < Parent
 
  def public_method
    "Redefined public method"
  end
 
  def call_private_method
    "Ancestor's private method: " + private_method
  end
 
end

Класс Parent является предком для класса Children, у которого переопределен метод public_method.

children = Children.new
children.public_method #=> "Redefined public method"
children.call_private_method #=> "Ancestor's private method: Private method"

Приватные методы предка можно вызывать из наследников.

JavaScript

var Parent = function( data ) {
    this.data = data || false;
    this.public_method = function() { return 'Public Method'; }
}
 
var Child = function() {
    this.public_method = function() { return 'Redefined public method'; }
    this.getData = function() { return 'Data: ' + this.data; }
}
 
Child.prototype = new Parent('test');
var Test = new Child();
 
Test.getData(); // => "Data: test"
Test.public_method(); // => "Redefined public method"
Test.data; // => "test"

Класс Parent является предком для класса Children, у которого переопределен метод public_method. В JavaScript используется прототипное наследование.

Конструкторы и деструкторы

В С++ конструкторы при наследовании вызываются последовательно от самого раннего предка до самого позднего потомка, а деструкторы наоборот — от самого позднего потомка до самого раннего предка.

class First
{
public:
    First()  { cout << ">>First constructor" << endl; }
    ~First() { cout << ">>First destructor" << endl; }
};
 
class Second: public First
{
public:
    Second()  { cout << ">Second constructor" << endl; }
    ~Second() { cout << ">Second destructor" << endl; }
};
 
class Third: public Second
{
public:
    Third()  { cout << "Third constructor" << endl; }
    ~Third() { cout << "Third destructor" << endl; }
};
 
// выполнение кода
Third *th = new Third();
delete th;
 
// результат вывода
/*
>>First constructor
>Second constructor
Third constructor
 
Third destructor
>Second destructor
>>First destructor
*/

См. также

Примечания

  1. о порядке разрешения метода в Python
  2. C# Language Specification Version 4.0, Copyright © Microsoft Corporation 1999—2010

Ссылки



Wikimedia Foundation. 2010.

Игры ⚽ Поможем написать реферат

Полезное


Смотреть что такое "Наследование (программирование)" в других словарях:

  • Наследование — это процесс передачи имущества (наследства, наследственного имущества) умершего к другим лицам. Наследование: Наследование (биология) Наследование (право) Наследование (программирование) Множественное наследование и его виды: Ромбовидное… …   Википедия

  • Наследование (значения) — Наследование (программирование) Наследование (право) …   Википедия

  • НАСЛЕДОВАНИЕ — переход прав и обязанностей умершего (наследователя) к его наследникам. В порядке НАСЛЕДОВАНИЯ переходят главным образом право собственности, а также другие имущественные права и обязанности, которые составляют содержание обязательственных,… …   Финансовый словарь

  • Программирование основанное на прототипах — Прототипное программирование стиль объектно ориентированного программирования, при котором отсутствует понятие класса, а повторное использование (наследование) производится путём клонирования существующего экземпляра объекта прототипа.… …   Википедия

  • Класс (программирование) — У этого термина существуют и другие значения, см. Класс. Класс в программировании набор методов и функций. Другие абстрактные типы данных  метаклассы, интерфейсы, структуры, перечисления  характеризуются какими то своими, другими… …   Википедия

  • Виртуальное наследование — У этого термина существуют и другие значения, см. Наследование. Про наследование виртуальных методов, см виртуальный метод. Виртуальное наследование (англ. virtual inheritance) в языке программирования C++  один из вариантов… …   Википедия

  • Полиморфизм (программирование) — У этого термина существуют и другие значения, см. Полиморфизм. Эта статья или раздел нуждается в переработке. Пожалуйста, улучшите статью …   Википедия

  • Суперкласс (программирование) — Основная статья: Наследование (программирование) В программировании суперклассом или родительским классом называют класс, на основе которого создаются другие классы. Классы, полученные на основе суперкласса, называются дочерними классами,… …   Википедия

  • Множественное наследование — У этого термина существуют и другие значения, см. Наследование. Множественное наследование  свойство, поддерживаемое частью объектно ориентированных языков программирования, когда класс может иметь более одного суперкласса (непосредственного …   Википедия

  • Ромбовидное наследование — У этого термина существуют и другие значения, см. Наследование. Диаграмма наследования классов в виде ромба. Ромбовидное наследование ( …   Википедия


Поделиться ссылкой на выделенное

Прямая ссылка:
Нажмите правой клавишей мыши и выберите «Копировать ссылку»