С++: переопределение public\private inheritance
Если B
наследует от A
с помощью public
, может ли B
переопределить одну из функций и заставить ее быть закрытой?
class A
{
public:
virtual double my_func1(int i);
virtual double my_func2(int i);
}
class B : public A // Notice the public inheritance
{
public:
virtual double my_func1(int i);
private:
virtual double my_func2(int i);
}
Как насчет другого пути? если тип наследования является закрытым - может B
принудительно открыть определенную функцию?
Что делать, если A
является чисто абстрактным? это имеет значение?
Будет ли protected
иметь какое-либо значение в любой комбинации?
Ответы
Ответ 1
Если B наследует от A, использующего public, может ли B отменить одну из функций и заставить ее быть закрытой?
НЕТ
Несмотря на то, что my_func1()
объявляется в priavte
спецификаторе доступа, он может быть вызван через указатель на class A
, фактически указывая на объект class B
Вызов my_func1()
оценивается во время выполнения в зависимости от типа объекта, указанного указателем. Во время компиляции компилятор видит вызов my_func1()
как вызов A::my_func1()
, и поскольку A::my_func1()
является общедоступным, компилятор не сообщает только об ошибке. Только во время выполнения вычисляется фактический вызов функции B::my_func1()
.
Конечно, вы не можете напрямую вызвать my_func1()
через объект class B
, хотя, поскольку B::my_func1()
объявляется в спецификаторе Private Access, и вы не можете получить доступ к частным объявленным членам вне класса.
Как насчет другого пути? если тип наследования является приватным - может ли B заставить определенную функцию быть общедоступной?
НЕТ
Если вы вызываете my_func1()
через указатель Base class A
, во время компиляции он просто оценивается как вызов A::my_func1()
, который Invalid
, так как A::my_func1() is declared private in
класс A`
Что делать, если A является чисто абстрактным? это имеет значение?
NO
Не имеет значения, является ли базовый класс абстрактным или просто полиморфным. Эти же правила будут применимы.
Защищено ли какое-либо различие в любой комбинации?
NO
Как объяснялось в первых 2 Q, если вы вызываете виртуальную функцию с полным указателем на базовый класс, тогда во время компиляции только проверка доступа к этой функции-члену в классе Base, потому что компилятор видит ее как вызов функции члена класса Base. Фактический вызов функции оценивается в run time
, и эта функция называется Runtime Polymorphism
или Dynamic polymorphism
, которая не зависит от спецификаторов Access, которая как конструктор времени компиляции.
Итак, в заключение,
переопределяющие элементы базового класса не влияют на доступ
Ответ 2
Разница
Что делать, если A является чисто абстрактным? это имеет значение?
Единственное отличие, которое он делает, следующее: i.e как они могут (или не могут) использоваться:
A *pa = new B();
pa->my_func2(10); //calls B::my_func2() even though its private!
B *pb = new B();
pb->my_func2(10); //compilation error - trying to access private function
Объяснение
Спецификаторы доступа - это конструкция времени компиляции, и поэтому компилятор обнаруживает любое нарушение правил доступа во время компиляции (очевидно) на основе статического типа объекта (или указателя). Такое нарушение не может быть обнаружено во время выполнения.
Итак, pa->my_func2()
работает, потому что компилятор видит, что статический тип pa
есть A*
, который имеет общую функцию my_func2()
, поэтому выражение pa->my_func2()
передает тест компилятора. Следовательно, он работает.
Но pb->my_func2()
не работает, поскольку статический тип pb
есть B*
, который имеет частную функцию my_func2()
, поэтому код даже не компилируется!
Ответ 3
То, что вы переопределяете, не влияет на доступ. Таким образом, вы можете создать публичное переопределение частной унаследованной функции точно так же, как вы создаете закрытое переопределение публично унаследованной функции.
Общественное переопределение частной унаследованной функции, очевидно, должно вызывать реальную функцию, и она должна быть встроенной, поэтому компилятор будет оптимизировать ее.
Ответ 4
==> If B inherits from A using public, can B override one of the functions and force it to be private?
НЕТ. Указатель/ссылка на A
всегда будет видеть my_func2
как общедоступный. Вы все равно можете вызвать этот метод, используя A*
или A&
. (то, что вы спрашиваете, возможно на Java).
==> if the inheritance type is private - can B force a specific function to be public?
На первом месте, если тип наследования является конфиденциальным/защищенным, вы не можете назначить объект класса Derived указателю/ссылке базового класса. например вы не можете сделать следующее!
A* p = new B; // error
==> What if A is pure abstract? does it make a difference?
Разница NO (за исключением того, что вы должны определять методы в B
)
==> Would protected make any difference in any combination?
Разность NO (относительно класса Base)
Ответ 5
Я просматривал сообщения, сделанные другими, и нашел объяснение, связанное с ошибками, возникающими, когда наследование было private/protected
в классе Derived несколько запутанным/неполным.
Рассмотрим ниже фрагмент кода,
class A
{
public:
virtual double my_func1(int i);
virtual double my_func2(int i);
}
class B : private A // Notice private inheritance
{
public:
virtual double my_func1(int i);
private:
virtual double my_func2(int i);
}
A* ptr = new B; // this is not legal because B has a private base
ptr->my_func1(); // my_func1() is not accessible
ptr->my_func2(); // my_func2() is also not accessible not because it is private but due
// base class A being inherited privately
Итак, когда мы наследуем class B
от class A
с помощью спецификаторов private/protected
, то это означает, что никто из внешнего мира не знает, что class B
унаследовал от class A
, следовательно, незаконно назначать pointer/reference
типа class B
указателю/ссылке типа class A
. Следовательно, доступ частной/защищенной переопределенной виртуальной функции в производных классах действителен только при наследовании в public
.