April 17, 2020

Merhaba. Şöyle bir kodum var:

class Foo;
class A;

class Base
{
public:
 static A a;
public:
 virtual void handle(Foo& foo) = 0;
};

class A : public Base
{
public:
 void handle(Foo& foo) override;
};

class Foo
{
private:
 Base* _cls;
public:
 void set(A* cls);
};

//////////////////////////////

void Foo::set(A* cls)
{
 _cls = cls;
}

void A::handle(Foo& foo)
{
 foo.set(&Base::a);
}

Bu kodu derlemeye çalıştığımda şu hatayı alıyorum:

error: LNK2001: Çözümlenmemiş dış sembol "public: static class A Base::a" (?a@Base@@2VA@@A)
error: LNK1120: 1 çözümlenmemiş dışlar

Bu hatanın 'Base' soyut sınıfı içerisinde tanımlı olan 'static A a' veri üyesinin ilk değerinin verilmemesi olduğunu tahmin ediyorum. Çünkü static veriyi 'static int a' olarak tanımlayıp daha sonra ilk değerini vermezsek aynı hata oluşuyor. Eğer ilk değerini verirsek kod sorunsuz derleniyor. İlkel veri türlerine ilk değer vermek kolay ama kullanıcı tanımlı sınıf türü kullanan sınıflara ilk değer vermek biraz farklı. Mesela kurucu fonksiyon ile ilk değer verilebiliyor:

class StaticStuff
{
    std::vector<char> letters_;

public:
    StaticStuff()
    {
        for (char c = 'a'; c <= 'z'; c++)
            letters_.push_back(c);
    }
};

class Elsewhere
{
   static StaticStuff staticStuff;
};

// Kaynak: https://stackoverflow.com/questions/1197106/static-constructors-in-c-i-need-to-initialize-private-static-objects/1197129#1197129

Lakin benim kodumda görüldüğü üzere 'A' sınıfı herhangi bir veri değişken barındırmıyor. Haliyle ilk değer verilmesi gereken bir şey olmuyor. Esasında A sınıfının örnekleri (instance) de bir nevi bayrak (flag) yerine kullanılıyor ama tabii ki enum gibi değil, daha kapsamlı. Yani direkt static örnek oluşturup niçin ilk değer vermeden kullanamıyoruz? Sonuçta sadece tuttukları adreslerle ilgileniyorum. Static olmayan veri üyelerde ilk değer vermem gerekmiyor ama. Kodun derlenebilmesi için nasıl yöntemler izlemeliyim?

Teşekkürler.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 17, 2020

Bu konu ilk değerle değil, Base::a'nın nerede tanımlandığının bildirilmemiş olmasıyla ilgili. Yani, Base::a'yı oluşturan bitler nerede?

C++ gibi diller farklı derlenmiş olan parçalardan oluştuklarından base.h dosyası doğal olarak birden fazla dosya tarafından kullanılıyor alabilir. Bu dosyalar derlenirken bilinen tek şey, Base nesnelerinin ortak olarak kullandıkları 'a' adında A türünde tek bir değişken var. Ancak, derlenmekte olan dosyaların hiçbirisi o değişkenin bitlerinin nerede olduğuna kendisi karar veremez. Verebilseydi, ortalıkta birden fazla Base::a olurdu ve programın farklı parçaları farklı bitlerle oynarlardı.

O yüzden, 'static' anahtar sözcüğünün söylediği şu: "bir yerde bir Base::a var". Onu kullanan kod da şunu söylemiş oluyor: "bahsedilen Base::a'yı şöyle kullanıyorum." O Base::a'nın tanımını tek noktada yapmak programcıya kalıyor. Sınıf tanımının dışında ve normalde örneğin base.cpp dosyasına 'A Base::a;' yazıyoruz. Bundan sonrası bağlayıcının (linker) görevi: Programın "Base::a'yı kullanıyorum" diyen noktalarını o değişkenin nerede olduğunu bağlama zamanında bilerek o değişkene bağlıyor.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]