Pergunta

Considere o seguinte código C ++:

class A
{
public:
      virtual void f()=0;
};


int main()
{
     void (A::*f)()=&A::f;
}

Se eu tivesse que adivinhar, diria que o & A :: f neste contexto significaria "o endereço da implementação do A de f ()", já que não há separação explícita entre ponteiros para funções e membros regulares funções membro virtuais. E já que um não implementa f (), que seria um erro de compilação. No entanto, não é.

E não só isso. O código a seguir:

void (A::*f)()=&A::f;
A *a=new B;            // B is a subclass of A, which implements f()
(a->*f)();

vai realmente chamar B :: f.

Como isso acontece?

Foi útil?

Solução

Aqui é demais informações sobre ponteiros de função de membro. Há algumas coisas sobre funções virtuais em "Os bem-comportados Compiladores", embora IIRC quando li o artigo que eu estava roçando a parte, uma vez que o artigo é realmente sobre a implementação de delegados em C ++.

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

A resposta curta é que ele depende do compilador, mas uma possibilidade é que o ponteiro de função de membro é implementada como uma estrutura que contém um ponteiro para uma função de "conversão", que faz a chamada virtual.

Outras dicas

Ele funciona porque o padrão diz que é assim que deve acontecer. Eu fiz alguns testes com GCC, e verifica-se para as funções virtuais, CCG armazena a tabela virtual deslocamento da função em questão, em bytes.

struct A { virtual void f() { } virtual void g() { } }; 
int main() { 
  union insp { 
    void (A::*pf)();
    ptrdiff_t pd[2]; 
  }; 
  insp p[] = { { &A::f }, { &A::g } }; 
  std::cout << p[0].pd[0] << " "
            << p[1].pd[0] << std::endl;
}

Esse programa saídas 1 5 - os deslocamentos byte da tabela entradas virtuais dessas duas funções. Segue-se o Itanium C ++ ABI , que especifica que .

Eu não sou inteiramente certo, mas eu acho que é o comportamento polimórfico apenas regular. Eu acho que &A::f realmente significa o endereço do ponteiro de função em vtable da classe, e é por isso que você não está recebendo um erro do compilador. O espaço no vtable ainda é alocada, e que é o local que você está realmente ficando para trás.

Isso faz sentido porque as classes derivadas essencialmente substituir estes valores com ponteiros para as suas funções. É por isso que (a->*f)() trabalha em seu segundo exemplo -. f está referenciando o vtable que é implementado na classe derivada

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top