5 Mayıs 2016 Perşembe

Virtual Metodlar

Virtual Table - VTable
C++ standardı polymorphism'in (çok biçimlilik) nasıl gerçekleşeceğini tanımlamaz. Ancak tüm derleyiciler vtable yöntemini kullanıyorlar. Bir gün başka bir üretici yeni bir yöntemle karşımıza çıkabilir.

Virtual metodlar derleyicinin sınıf için vtable üretmesine sebep olur. VTable bilgisinin nerede saklanacağı standart tarafından belirlenmiyor.

Microsoft derleyicisi şu şekilde saklıyor. Elimizde şöyle bir kod olsun.
class A {
  virtual Ax() {}
  int a, b;
};
class B {
  virtual Bx() {}
  int c, d;
};
class C : public A, public B {
  int foo, bar;
};
Object yerleşimi şöyledir.
A's VTable ptr
A's member variables.
B's Vtable ptr
B's member variables.
C's member variables.
Gcc ise vtable bilgisini object'in en sonuna yerleştirir.

De-Virtualization
Metodun virtual olmasına rağmen, derleyici tarafında vtable kullanılmasına gerek olmadığının tespit edilmesi ve verimlilik adına direkt çağrı haline getirilmesidir. Açıklaması şöyle
If the compiler can detect at compile-time that a particular call to a virtual member function, through a polymorphic type, will undeniably call a specific version of that function, then it is allowed avoid using the virtual dispatching logic, calling the function statically. That's behaving "as if" it had used the virtual dispatching logic, since the compiler can prove that this is the function that would have been called.

As such, the standard does not define when de-virtualization is allowed/forbidden....

Virtual Metodların Access Modifier Değiştirmesi
Ata sınıfta public olan bir virtual metodun, kalıtan sınıfta private yapılması. Bu kullanım şeklini hiç sevmiyorum ama bazı insanlar inatla kullanıyorlar. Şöyle yapılır
#include <iostream>

class A {
public:
  virtual void f() { std::cout << "virtual_function"; }
};

class B : public A {
private:
  void f() { std::cout << "private_function"; }
};

void C(A &g) { g.f(); }

int main() {
  B b;
  C(b);
}
Bir başka örnek
struct A {
    A(){ }
    virtual ~A(){ }
    A(A&&){ }
public:
    virtual void bar(){ std::cout << "A" << std::endl; }
};

struct B : public A{
private:
    virtual void bar(){ std::cout << "B" << std::endl; }
};

int main()
{
    A *a = new B;
    a -> bar(); //prints B
}
Java virtual bir metodun access modifier değiştirmesine izin vermiyor ve bence çok ta iyi yapıyor.
public class A{
    public void foo(){ }
}

public class B extends A{
    @Override
    private void foo(){ }  //compile-error
}

Pure Virtual
Diğer programlama dillerinde abstract diye bir anahtar kelime ile metodun pure virtual olduğu belirtilir. C++'ta şöyle belirtilir.
virtual void MyFunction() = 0; 
Aslında şöyle de yapılabilirdir.
pure virtual void MyFunction();
Sebebibini Bjarne Stroustrup şöyle açıklamış.
The curious = 0 syntax was chosen over the obvious alternative of introducing a new keyword pure or abstract because at the time I saw no chance of getting a new keyword accepted. Had I suggested pure, Release 2.0 would have shipped without abstract classes. Given a choice between a nicer syntax and abstract classes, I chose abstract classes. Rather than risking delay and incurring the certain fights over pure, I used the tradition C and C++ convention of using 0 to represent not there.
Yani tartışmalar daha fazla uzamasın istemiş.

Ata Sınıfta Pure Virtual Olmayan Bir Metod Sonradan Pure Virtual Yapılabilir
Saçma ama yine de yapılabiliyor. B metodu ilk ata sınıfımız. Bundan D kalıtır ve foo() metodunu pure virtual hale getirir. Böylece D'den kalıtan G foo() metodunu override etmek zorunda kalır.
class B // from a third party
{
public:
   virtual void foo();
};

class D : public B
{
public:
   void foo() override = 0; // allowed by gcc 4.8.2
   virtual void bar() = 0;
};

class G : public D
{
public:
   // forgot to reimplement foo
   void bar() override;
};

int main()
{
   G test;  // compiler error is desired
}





Hiç yorum yok:

Yorum Gönder