Yazılım geliştirmede deyimler: kovaryant dönüş tipi

Adanali

Active member
Yazılım geliştirmede deyimler: kovaryant dönüş tipi


  1. Yazılım geliştirmede deyimler: kovaryant dönüş tipi

Bir üye işlevin kovaryant dönüş türü, geçersiz kılan bir üye işlevin daha kısıtlı bir tür döndürmesine izin verir. Bu, özellikle C++’da prototip modeli uygularken önemlidir.








Kovaryant dönüş tipini daha önceki yazılarımda zaten kullanmıştım ama detaylı olarak anlatmadım. Bugün ona ulaşacağım.

Kovaryant dönüş türü


Saf bir uygulama ile başlayacağım.

saf versiyon


Aşağıdaki program covariantReturnType.cpp prototip modeli uygular.


// covariantReturnType.cpp

#include <iostream>
#include <string>

class Window{ // (1)
public:
virtual Window* clone() {
return new Window(*this);
}
virtual std::string getName() const {
return "Window";
}
virtual ~Window() {};
};

class DefaultWindow: public Window { // (2)
DefaultWindow* clone() override {
return new DefaultWindow(*this);
}
std::string getName() const override {
return "DefaultWindow";
}
};

class FancyWindow: public Window { // (3)
FancyWindow* clone() override {
return new FancyWindow(*this);
}
std::string getName() const override {
return "FancyWindow";
}
};

Window* cloneWindow(Window& oldWindow) { // (4)
return oldWindow.clone();
}

int main() {

std::cout << 'n';

Window window;
DefaultWindow defaultWindow;
FancyWindow fancyWindow;

const Window* window1 = cloneWindow(window);
std::cout << "window1->getName(): " << window1->getName() << 'n';

const Window* defaultWindow1 = cloneWindow(defaultWindow);
std::cout << "defaultWindow1->getName(): " << defaultWindow1->getName() << 'n';

const Window* fancyWindow1 = cloneWindow(fancyWindow);
std::cout << "fancywindow1->getName(): " << fancyWindow1->getName() << 'n';

delete window1;
delete defaultWindow1;
delete fancyWindow1;

std::cout << 'n';

}


Arayüzün sınıfı Window (satır 1) sanal clone-İşlev. ONLAR cloneişlev kendisinin bir kopyasını döndürür. Gibi türetilmiş sınıflar DefaultWindow (satır 2) e FancyWindow (satır 3) ayrıca kendisinin bir kopyasını döndürür. İşlev cloneWindow (satır 4) sanal üye işlevini kullanır ve kullanılanın klonlarını oluşturur Window. Bende de sanal var getName-Sanal gönderimi görüntülemek için uygulanan işlev.


Program çıktısı henüz sürpriz içermiyor:








Bu örnekte kovaryant dönüş türünün kullanımı açık mı? sanal clone-Fonksiyonu Window birini verir Window– İşaretçi geri ama sanal clone-Fonksiyonu DefaultWindow A DefaultWindow– İşaretçiler ve sanal clone-Fonksiyonu FancyWindow bir FancyWindow işaretçisi. Bu, veri türünün kovaryant olduğu anlamına gelir: Türetilmiş bir sınıf işlevi, geçersiz kılınan temel sınıf işlevinden daha fazla türetilmiş bir tür döndürdüğünde, türetilmiş sınıfın dönüş türüne kovaryant denir.

Ayrıca belirtmek istediğim küçük bir tuhaflık var: sanal üyenin özellikleri clone itibaren DefaultWindow VE FancyWindows özeldir, işlev cloneWindow (satır 4) onları arayın. Nedeni basit: üyelik fonksiyonu cloneWindow arayüz sınıfının genel arayüzünü kullanır Window.

Ama neden bu uygulama biçimini saf olarak adlandırdım?

sahip olma semantiği


Genel olarak, uygulanması clone– İşlev bilinmiyor. clone aa’ya bir işaretçi döndürür Window geri dönmek. İşaretçiler doğası gereği kusurludur; tamamen farklı iki semantiği modellerler: mülkiyet ve borç verme.

  • mülk: Arayan bunun için Window sorumlu ve onu yok etmelidir; bu programın davranışıdır covariantReturnType.cpp modellenmiş
  • Ödünç vermek: Arayan bunun içindir Window yönetici ve arayandan ödünç alır.
Şunu bir kez daha vurgulayayım:

  • Mal sahibi: Sahibi sizsiniz Window. Onunla ilgilenmeli ve onu yok etmelisin. Değilse, bir bellek sızıntısına neden oluyorsunuz.
  • borçlu: Sahibi değilsiniz Window. Onu yok edemezsin. Onu yok etmek, çifte elemeye neden olur.
C++11 ile bu işaretçi sorunundan kolayca kaçınılabilir: ikisinden birini kullanın std::unique_ptr veya bir std::shared_ptr.

std::unique_ptr


dönüşü bir std::unique_ptr arayanın sahibi olduğu anlamına gelir. ONLAR std::unique_ptr yerel bir değişken gibi davranır. Kapsam dışına çıkarsa, otomatik olarak yok edilir. Ayrıca, kovaryant dönüş tipini simüle edebilirsiniz.


// covariantReturnTypeUniquePtr.cpp

#include <iostream>
#include <memory>
#include <string>

class Window{
public:
virtual std::unique_ptr<Window> clone() {
return std::make_unique<Window>(*this); // (1)
}
virtual std::string getName() const {
return "Window";
}
virtual ~Window() {};
};

class DefaultWindow: public Window {
std::unique_ptr<Window> clone() override {
return std::make_unique<DefaultWindow>(*this); // (2)
}
std::string getName() const override {
return "DefaultWindow";
}
};

class FancyWindow: public Window {
std::unique_ptr<Window> clone() override {
return std::make_unique<FancyWindow>(*this); // (3)
}
std::string getName() const override {
return "FancyWindow";
}
};

auto cloneWindow(std::unique_ptr<Window>& oldWindow) {
return oldWindow->clone();
}

int main() {

std::cout << 'n';

std::unique_ptr<Window> window = std::make_unique<Window>();
std::unique_ptr<Window> defaultWindow = std::make_unique<DefaultWindow>();
std::unique_ptr<Window> fancyWindow = std::make_unique<FancyWindow>();

const auto window1 = cloneWindow(window);
std::cout << "window1->getName(): " << window1->getName() << 'n';

const auto defaultWindow1 = cloneWindow(defaultWindow);
std::cout << "defaultWindow1->getName(): " << defaultWindow1->getName() << 'n';

const auto fancyWindow1 = cloneWindow(fancyWindow);
std::cout << "fancyWindow1->getName(): " << fancyWindow1->getName() << 'n';

std::cout << 'n';

}


Sanalın dönüş türü cloneişlev şimdi std::unique_ptr<Window>ve iade edilen öğe bir std::make_unique<Window>(*this) (satır 1), bir std::make_unique<DefaultWindow>(*this) (2. satır) veya bir std::make_unique<FancyWindow>(*this) (3. satır).

Programın çıktısı öncekiyle aynı kalır:








Bütünlük için bir eklemek istiyorum std::shared_ptr uygulamak.

std::shared_ptr


dönüşü bir std::shared_ptr arayanın ve arananın mülkiyeti paylaştığı anlamına gelir. Ne arayan ne de aranan den std::shared_ptr daha fazlasına ihtiyaç duyarsanız, otomatik olarak yok edilecektir.


// covariantReturnTypeSharedPtr.cpp

#include <iostream>
#include <memory>
#include <string>

class Window{
public:
virtual std::shared_ptr<Window> clone() {
return std::make_shared<Window>(*this);
}
virtual std::string getName() const {
return "Window";
}
virtual ~Window() {};
};

class DefaultWindow: public Window {
std::shared_ptr<Window> clone() override {
return std::make_shared<DefaultWindow>(*this);
}
std::string getName() const override {
return "DefaultWindow";
}
};

class FancyWindow: public Window {
std::shared_ptr<Window> clone() override {
return std::make_shared<FancyWindow>(*this);
}
std::string getName() const override {
return "FancyWindow";
}
};

auto cloneWindow(std::shared_ptr<Window>& oldWindow) {
return oldWindow->clone();
}

int main() {

std::cout << 'n';

std::shared_ptr<Window> window = std::make_shared<Window>();
std::shared_ptr<Window> defaultWindow = std::make_shared<DefaultWindow>();
std::shared_ptr<Window> fancyWindow = std::make_shared<FancyWindow>();

const auto window1 = cloneWindow(window);
std::cout << "window1->getName(): " << window1->getName() << 'n';

const auto defaultWindow1 = cloneWindow(defaultWindow);
std::cout << "defaultWindow1->getName(): " << defaultWindow1->getName() << 'n';

const auto fancyWindow1 = cloneWindow(fancyWindow);
std::cout << "fancyWindow1->getName(): " << fancyWindow1->getName() << 'n';

std::cout << 'n';

}


Örnek bağlantı noktası covariantReturnTypeUniquePtr.cpp İçinde covariantReturnTypeSharedPtr.cpp bu çocuk oyuncağı: Ben sadece değiştiririm unique Başından sonuna kadar shared. Beklendiği gibi, bu aşağıdaki program çıktısıyla sonuçlanır:








Sıradaki ne?


Bir sonraki makalem biraz yerinde değil, çünkü çok biçimlilik ve şablonlarla ilgili deyimler hakkında zaten yazılmış olan her şeyin bir özetini vereceğim.


(harita)



Haberin Sonu
 
Üst