cpp

Композиция структур

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

Чтобы расширить производную структуру достаточно вместо названия поля и его типа указать название базовой структуры:

type A struct { // Базовая структура
   X int
}
type B struct { // Производная структура
   Y int
   A
}

В этом случае структура B получает (можно сказать наследует) весь функционал структуры A. Создадим экземпляр структуры B:

objB := B{Y: 10, A: A{X: 20}}

Как видно из примера, при инициализации название структуры A указывается в качестве названия поля. Поля и методы структуры A становятся полями и методами структуры B, поэтому мы можем обратиться к ним напрямую с помощью точечной нотации:

fmt.Println(objB.X)        // 20
fmt.Println(objB.Y)        // 10

Получить доступ к членам базовой структуры можно также через название базовой структуры:

fmt.Println(objB.A.X)      // 20

Это особенно полезно, если в базовой и производной структурах существует метод с одинаковым названием. В этом случае метод производной структуры переопределяет метод базовой структуры:

objB.test()                // (b B) test()

Чтобы вызвать метод базовой структуры, нужно обратиться к нему через название базовой структуры:

objB.A.test()              // (a A) test()

Пример использования композиции приведен в листинге 11.8.

Листинг 11.8. Композиция

package main

import "fmt"

type A struct { // Базовая структура
   X int
}
type B struct { // Производная структура
   Y int
   A
}

func main() {
   objB := B{Y: 10, A: A{X: 20}}
   fmt.Println(objB)          // {10 {20}}
   fmt.Println(objB.X)        // 20
   fmt.Println(objB.A.X)      // 20
   fmt.Println(objB.Y)        // 10
   fmt.Println(objB.GetX())   // 20
   fmt.Println(objB.A.GetX()) // 20
   fmt.Println(objB.GetY())   // 10
   objB.test()                // (b B) test()
   objB.A.test()              // (a A) test()
}
func (a A) GetX() int {
   return a.X
}
func (b B) GetY() int {
   return b.Y
}
func (a A) test() {
   fmt.Println("(a A) test()")
}
func (b B) test() {
   fmt.Println("(b B) test()")
}

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

Листинг 11.9. Множественная композиция

package main

import "fmt"

type A struct {
   X int
}
type B struct {
   X int
}
type C struct {
   A
   B
}

func main() {
   objC := C{A: A{X: 20}, B: B{X: 10}}
   fmt.Println(objC)        // {{20} {10}}
   // fmt.Println(objC.X)   // Ошибка!
   fmt.Println(objC.A.X)    // 20
   fmt.Println(objC.B.X)    // 10
   // objC.test()           // Ошибка!
   objC.A.test()            // (a A) test()
   objC.B.test()            // (b B) test()
}
func (a A) test() {
   fmt.Println("(a A) test()")
}
func (b B) test() {
   fmt.Println("(b B) test()")
}
/*
func (c C) test() {
   c.B.test()
}
*/

Учебник Go (Golang)
Учебник Go (Golang) в формате PDF

Реквизиты

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов

cpp