comprobación de control de acceso a la función ocurre en la etapa posterior de un C++ llamada a la función. El orden en el nivel alto sería como la búsqueda de nombre, la deducción del argumento de la plantilla (si existe), la resolución de sobrecarga, y luego el control de acceso (público/proteger/privado).
Pero en su fragmento, usaba un puntero a la clase base y la función f() en la clase base es pública, eso es lo que el compilador puede ver en el compilador, así que el compilador dejará pasar su fragmento.
A *ptr = new B;
ptr->f();
Pero todos los anteriores ocurren en tiempo de compilación, por lo que son realmente estáticos. Mientras que la llamada de función virtual a menudo potenciada por vtable & vpointer son cosas dinámicas que ocurren en tiempo de ejecución, la llamada de función virtual es ortogonal al control de acceso (la llamada de función virtual ocurre después del control de acceso), por eso la llamada a f() terminó B :: f() independientemente de que el control de acceso sea privado.
Pero si intenta utilizar
B* ptr = new B;
ptr->f()
Esto no pasará a pesar de la viable vpointer &, compilador no permitirá que se compile en tiempo de compilación.
Pero si se intenta:
B* ptr = new B;
((static_cast<A*>(ptr))->f();
esto iba a funcionar muy bien.
No es una violación de LSP, porque un objeto B se puede usar en cualquier lugar donde pueda A. Tales contextos desencadenan una conversión implícita Derivado a Base, posiblemente cortando las partes adicionales. Después de dicha conversión, se accede a 'B :: f' como' A :: f', que es público. – MSalters
@MSalters: hay dos tipos diferentes de sustitución en C++, porque hay (al menos) dos tipos diferentes de polimorfismo en C++. Podemos evaluar por separado si LSP se aplica a cada uno. Si su objeto B es, por ejemplo, pasado por valor en una llamada de función que utiliza la deducción de argumentos de la plantilla para crear una instancia de la función a partir de una plantilla, entonces bien podría no cortarse, y de hecho accedería a 'f' como' B :: f'. B no satisface todos los conceptos que A satisface, básicamente, por lo que los objetos solo son sustituibles una vez que el tipo ha sido eliminado (por ejemplo, usando un A * o convirtiéndolo en A). –
LSP es un principio de OOP que restringe _conformance conformance_. El contexto de la plantilla no es un contexto OOP normal. Es programación genérica, que generalmente ignora la herencia. En cambio, usa _conformidad estructural_. Por lo tanto, el principio LSP de OOP no se aplica a los parámetros de plantilla. – MSalters