6 Kasım 2017 Pazartesi

Virtual Inheritance

Virtual Inheritance
Açıklaması şöyle
As with all virtual inheritance, the virtual bases are initialized by the most-derived object.
Virtual inheritance diamond veya daha karışık kalıtım ilişkisi varsa, alttaki sınıfların tek bir ata sınıf içermesi için kullanılır. Aslında tek bir ata sınıfın kullanılması Stroustrup tarafından desteklenmiyor.
 "Don’t immediately invent a unique base for all of your classes (an Object class). Typically, you can do better without it for many/most classes." (The C++ Programming Language Fourth Edition, Sec 1.3.4)
Örnek 
Şöyle yaparız
class base;
class d1 : virtual public base;
class d2 : virtual public base
class d3 : public d1, public d2;
Örnek
Elimizde şöyle bir hiyerarşi olsun.
            Model3D
            /       \
     Moveable3D   Nameable
           |         |
      Moveable       |
            \       /
             Object
Şöyle yaparız.
class Object{...];

class Nameable : public virtual Object{...};
class Moveable : public virtual Object{...};
class Moveable3D : public Moveable{...};
class Moveable2D : public Moveable{...};

class Model3D : public Movable3D, public Nameable{...};

Ata sınıfın metodunu çağırmak
Ata sınıfın f() metodu şöyle çağrılır.
class Model3D : public Moveable3D, public Nameable
{
    void f() 
    {
        Moveable3D::f();
    }
};
using anahtar kelimesi ile name lookup yapmak çoklu kalıtımda işe yaramaz.
using-declaration designates a base class member (and not a member subobject or a member function of a base class subobject), a using-declaration cannot be used to resolve inherited member ambiguities.
En Üst Sınıfın Constructor'ını Çağırmak
Açıklaması şöyle
"Because there is only a single instance of a virtual base class that is shared by multiple classes that inherit from it, the constructor for a virtual base class is not called by the class that inherits from it (which is how constructors are called, when each class has its own copy of its parent class) since that would mean the constructor would run multiple times. Instead, the constructor is called by the constructor of the concrete class"
Örnek
Elimizde şöyle bir kod olsun
class base;
class d1 : virtual public base;
class d2 : virtual public base
class d3 : public d1, public d2;
En üst ata sınıfın move contructor'ını çağırmak için şöyle yaparız.
d3(d3 &&other)
    : base(std::move(other)),   // <== *you* initialize the base
      d1(std::move(other)),
      d2(std::move(other)) {}

Örnek
Eğer en üst ata sınıfın constructor metodu parametre alıyorsa, en alttaki sınıf tarafından çağrılması gerekir. Şöyle yaparız
class A {
public:
   A(int) {}
};

class B: virtual public A {
public:
   B(): A(0) {}
};

// most derived class
class C: public B {
public:
  C(): A(0) {} // OK!!!
};
Şu kod derlenmez. Ara kademedeki sınıfların en üst ata sınıfın constructor'ını çağırmaması gerekir.
class A {
public:
  A(int) {}
};

class B0: virtual public A {
public:
  B0(): A(0) {}
};

class B1: virtual public A {
public:
  B1(): A(1) {}
};

class C: public B0, public B1 {
public:
  C() {} // How is A constructed? A(0) from B0 or A(1) from B1?
};
Örnek
Şimdi concrete class tarafından en üstteki ata sınıfın constructor metodunun çağrıldığını test edelim. Şöyle bir sınıfımız olsun. Bu kod derlenmez. Çünkü FailsToDerive sınıfının constructor metodu, Sealed sınıfının constructor metodunu çağırmaz! Virtual Inheritance olduğu için ClassSealer sınıfının constructor metodunu çağırır. Ancak bu sınıf private olduğu için erişemez ve derleme hatası alırız.
class ClassSealer {
private:
   friend class Sealed;
   ClassSealer() {}
};
class Sealed : public virtual ClassSealer
{ 
   // ...
};
class FailsToDerive : public Sealed
{
   // Cannot be instantiated
};
Eğer virtual inheritance olmasaydı sorunsuz derlendiğini görecektik.
class ClassSealer {
private:
   friend class Sealed;
   ClassSealer() {}
};
class Sealed : public ClassSealer
{ 
   // ...
};
class FailsToDerive : public Sealed
{
   // This class is capable of being instantiated
};
Base Class Destructor
"By the way, the constructors for virtual base classes are always called before the constructors for non-virtual base classes. This ensures that a class inheriting from a virtual base class can be sure the virtual base class is safe to use inside the inheriting class's constructor. The destructor order in a class hierarchy with a virtual base class follows the same rules as the rest of C++: the destructors run in the opposite order of the constructors. In other words, the virtual base class will be the last object destroyed, because it is the first object that is fully constructed."
Elmas Kalıtıma Alternatifler
CRTP bir seçenek olabilir denilmiş. Nasıl olduğuna dair bir fikrim yok.

Bazı Düşünceler
Elmas kalıtmını araştırırken belki kalıtımı yanlış anladığımı gördüm.
Some people believe that the purpose of inheritance is code reuse. In C++, this is wrong. Stated plainly, “inheritance is not for code reuse.”
Kalıtım aslında belli bir arayüze uyulacağını belirtmek için kullanılır deniliyor.



Hiç yorum yok:

Yorum Gönder