Apêndice B. Corte de objectos
Outro ponto que foi adiado do Capítulo 3 é que as classes base abstractas podem evitar o corte de objectos, o que será agora explicado. No resultado do Apêndice A, tanto a classe Base como a Derived são concretas, ou seja, qualquer uma delas pode ser instanciada por si só:
#include <cmath>
#include <iostream>
class Base
{
public:
virtual double trig_fcn(double x) const
{
return std::cos(x);
}
virtual ~Base() = default;
};
class Derived final : public Base
{
public:
double trig_fcn(double x) const override
{
return std::sin(x);
}
};
Supõe que agora criamos instâncias de cada um na pilha:
Base b; Derived d;
Supõe também que temos uma função que recebe um argumento Base e avalia a função membro trig_fcn(.) para e mostra o resultado no ecrã:
void slice_function(Base b)
{
using std::cout, std::format;
using namespace std::numbers;
cout << format("slice_function(.): trig_fcn(pi) = {}\n",
b.trig_fcn(pi));
}
Agora, chama esta função com b e d:
slice_function(b); slice_function(d);
Obteríamos como resultado algo como isto:
slice_function(.): trig_fcn(pi) = -1 slice_function(.): trig_fcn(pi) = -1
Em ambos os casos, o resultado é essencialmente -1 (isto pode não ser exato devido à aritmética de vírgula flutuante), o resultado de std::cos(pi), apesar de podermos esperar 0 para std::sin(pi) a partir do objeto Derived d .
Se tentarmos passar um objeto derivado para uma função que recebe um objeto base por valor, o código será compilado, mas o objeto derivado ...