4 Eylül 2019 Çarşamba

Object Slicing

Giriş
Object Slicing C++'ta nesneye yönelik programlamada karşımıza çıkar. C++'ta value semantics olduğu için gerçekleşir. Java gibi dillerde nesneler için reference semantics kullanıldığı için yoktur.

1. Metod Çağrısında Parametre
Metod çağrısında kalıtım varsa bile ata sınıf ilklendirilir ve kullanılır.

Örnek
Şöyle yaparız. Aslında bu örnek tam anlamıyla object slicing sayılmamalı çünkü bilinçli yazılmış bir koda benziyor.
void wantAnA(A myA)
{
   // work with myA
}

B derived;
// work with the object "derived"
wantAnA(derived);
Örnek
Elimizde şöyle bir kod olsun.
struct Foo
{
  virtual int operator()(void) { return 1; } 
};

struct Bar : public Foo
{
  virtual int operator()(void) override { return 2; }
};

int main()
{
  std::shared_ptr<Foo> p = std::make_shared<Bar>();
  std::cout << (*p)() << std::endl; //Çıktı olarak 2 verir

  std::function<int(void)> f;
  f = *p; //Problem burada
  std::cout << f() << std::endl; //Çıktı olarak 1 verir

  return 0;
}
Açıklaması şöyle. std::function<> değişkeni std::shared_ptr pointer aslında Bar olmasına rağmen Foo tipinden tanımlandığı için Foo gibi düşünür ve çalışır.
... given f = *p;, p is of type std::shared_ptr<Foo>, then the type of *p is Foo& (instead of Bar&).
2. Partial Initialization
Nesneye yönelik programlamada ata sınıf türünden olan bir değişkene kalıtılan bir nesnenin atanabilir. Böylece kalıtımdan dolayı gelen bilgilerin bir kısmı kaybedilmiş (sliced away) olur.

Örnek
Elimizde şöyle bir kod olsun.
class A {
   int foo;
};

class B : public A {
   int bar;
};
Şöyle yaparız.
B b;

A a = b;
Bu atamayı yaparsak a değişkeni b değişkeninin bar alanını içermeyecektir. Esasen bu nesneye yönelik kullanımda zaten beklenen bir davranıştır ve bence bir problem teşkil etmemelidir.

3. Esas Problem
Object Slicing'in oluşturduğu esas problem
A a = b;
A2& a2 = b2;
a2 = b;
şeklinde kullanımda ortaya çıkıyor. C++ assignment operator'ünü virtual kullanmadığı için a2 aslında b nesnesi olmasına rağmen, A'nın assignment operatörü çağrılır. Dolayısıyla b nesnesi yarım (partial) olarak ilklendirilir.

4. Engelleme
Object Slicing engellenebilir.

Örnek
Elimizde şöyle bir kod olsun.
struct foo { int a; };
struct bar : foo { int b; };

int main() {
    bar x{1,2};
    foo y = x; // <- I dont want this to compile!
}
Şöyle yaparız
struct foo 
{ 
  int a; 
  foo() = default; // you have to add this because of the template constructor

  template<typename T>
  foo(const T&) = delete; // error trying to copy anything but a foo

  template<typename T>
  foo& operator=(const T&) = delete; // error assigning anything else but a foo
};


Hiç yorum yok:

Yorum Gönder