класс может наследоваться от структуры, а структура от класса в классе по умолчанию наследование приватное, в структуре публичное приватность никак не влияет на наличие полей в наследнике, они есть всегда, просто могут быть недоступны
модификаторы доступа полей:
protected - этот член класса доступен всем другим членам этого класса, всем друзьям и наследникам private - члены класса доступны только членам класса и друзьям public - доступно всем
модификаторы доступа наследования:
public - все внешние функции имеют доступ к наследуемым полям родителя private - только наследник и его друзья имеют доступ к родительской части protected - только наследник, его наследники и друзья имеют доступ к родительской части
частное предпочтительнее общего методы с таким же именем, как у родителя, затмевают родительский метод также и с полями, поля наследника более локальные Метод класса, если определён полностью внутри класса, помечается inline, это позволяет обходить ODR. Начиная C++17, inline можно использовать и с переменными для обхода ODR. Так, например, можно определять статические поля класса в хедере.
можно привнести protected методы в наследника через using:
using Base::protectedMethod; и тогда они будут доступны наравне с методами наследника. таким образом можно из внешних функций обращаться к защищённым полям родителя
также можно извне запретить методы родителя, поместив их в приватную область
если хотим принять в методе наследника класс, недоступный из-за приватности (его имя нельзя называть), то нужно передним написать ::, это явно укажет, что принимается внешний объект, а не обращение к запретному родителю
как хранятся в памяти: в порядке объявления, то есть сначала родительские части наличие методов (невиртуальных) не влияет на размер
EBO - Empty Base Optimization если родитель пустой (1б), то ему разрешается ничего не занимать в памяти (0б), тк это не противоречит правилу “у разных объектов разные адреса”
при конструировании сначала полностью создаётся объект родителя можно в конструкторе наследника сначала указать, чем инициализировать поля родителя если не указать, то родитель попытается сконструироваться по умолчанию деструкторы вызываются сначала у наследников, потом у родителей
если у родителя нет конструктора по умолчанию, то придётся самому вызвать другой конструктор
Derived(int x) : Base(x), x_(x) {};
так можно вызвать конструктор только ближайшего предка, более дальних можно только при виртуальном наследовании
с С++11 можно наследовать конструкторы, надо написать у Derived using Base::Base;
наследуются все конструкторы, кроме конструктора копирования и перемещения
если есть наследник, а функция принимает родителя, то ей можно подсунуть наследника
срезка при копировании (slicing): при отдаче в фунцию, принимающую родителя, наследника по значению, то вызовется конструктор base от derived а если по ссылке, то просто рассматривается наследник, будто бы это родитель
приведение наследника к родителю и обратно:
у reinterpret_cast строчка так выглядит для любых типов
static_cast вниз при приватном наследовании невозможен, тк факт наследования скрыт
static_cast от base к derived при виртуальном наследовании невозможен (CE), тк начало виртуального предка не найдём однако можно dynamic_cast (если предок полиморфный)
когда static_cast, dynamic_cast и reinterpret_cast дают разные результаты?
- каст вбок (CE, норм работает, UB)
- каст вниз при виртуальном наследовании, предок полиморфный (CE, норм, UB)
множественное наследование:
если у объекта 2 родителя, то приведение к родителю также будет работать, адрес начала родительской части может быть сдвинут. пример неявного каста одного указателя к другому, при котором численное значение указателя меняется
можно унаследовать 2 одинаковых поля, но CE будет только при обращении к ним (неоднозначное обращение). также и с методами, но если объявить более локальный метод, то всё норм, он затмит 2 родительских
diamond problem/ромбовидное наследование s.Granny::g - s.g - неоднозначное обращение s.Mom::g - норм
при любом касте к бабушке, например Granny& g= s; - CE по причине ambigouos cast этого можно избежать, сначала скастившись к маме, а потом к бабушке
при вызове бабушкиного метода также CE, ambigouos request, потому что метод может пользоваться полями класса, а непонятно, от какой бабушки достался этот метод
каст вбок запрещен (неизвестен сдвиг)
inacceseble base class (warning)
если унаследовать маму от бабушки и унаследовать сына от мамы и бабушки(2), то получится, что до прямой бабушки(2) нет синтаксиса, чтобы обратится (ну есть, reinterpret_cast и вручную сдвинуть указатель, но это нелегально)
виден, доступен, но нельзя обратиться
чуть сложнее, чем проблема ромбовидного наследования, но там мы хотя бы имели синтаксис, как обратиться к конктетной бабушке типо s.Mom::g; а здесь ну к бабушке1 также s.Mom::g, а к бабушке2? s.Granny::g снова ambigous
наследование от переменного числа родителей
virtual inheritance
polymorphism