Yazılımın Geliştirilmesinde Idioma: Covariant Return Türü
Bir üye işlevinin Covaric Dönüşü türü, üzerine yazmanın bir üye işlevinin daha dar bir tür döndürmesine izin verir. Bu, özellikle C ++ 'da prototip modelini uygularken önemli bir rol oynar.
Önceki makalelerime daha ayrıntılı olarak açıklamadan Covaric dönüş türünü zaten kullandım. Bugün ulaşacağım.
Tür Kovar dönüşü
Başlangıçta saf bir uygulamayla başlıyorum.
Saf versiyon
Aşağıdaki program covariantReturnType.cpp Prototip modelini kullanın.
// 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 sınıfı Window (Riga 1) sanal bir clone-İşlev. . clone-T işlev kendi bir kopyasını döndürür. Gibi türetilen sınıflar DefaultWindow (Satır 2) e FancyWindow (Satır 3) ayrıca kendisinin bir kopyasını da döndürür. İşlev cloneWindow (Satır 4) sanal üyenin işlevini kullanır ve kullanma klonları oluşturur Window. Ben de bir sanal var getName-Sanal sevkiyatı görüntülemek için uygulandı.
Program çıktısının henüz bir sürprizi yok:
Bu örnekte Covaric Geri Dönüş türünün kullanımı açıkça tanınabilir mi? Sanal clone– Window Bir tane verir Window-Her geri döndü, ama sanal clone– DefaultWindow A DefaultWindow-Pointer ve sanal clone– FancyWindow Süslü bir işaretçi. Bu, veri türünün Kovaryte olduğu anlamına gelir: Bir türev sınıf işlevi, üzerine yazılmış bir temel sınıf işlevine kıyasla başka bir türev türü döndürürse, türev sınıfının geri dönüşü türüne kovaryant denir.
Ayrıca altını çizmek istediğim küçük bir uzmanlık var: sanal üye çalışmasına rağmen clone itibaren DefaultWindow VE FancyWindows Onlar özel, işlev cloneWindow (Riga 4) Sizi arayın. Bunun nedeni basit: üye işlevi cloneWindow Arayüz sınıfının genel arayüzünü kullanın Window.
Ama neden bu uygulama biçimini naif olarak tanımladım?
Mülk
Genel olarak, clone-Funkure bilinmiyor. clone Birine bir işaretçi verir Window Geriye doğru. İşaretçilerin doğası gereği bir kusuru vardır; Tamamen farklı iki semantiği şekillendiriyorlar: mülkiyet ve kredi.
std::unique_ptr
Bir dönüş std::unique_ptr Bu, arayanın sahibi olduğu anlamına gelir. . std::unique_ptr Yerel bir değişken gibi davranır. Bu, bölgenizi terk ederse, otomatik olarak yok edilecektir. Covaric geri dönüşü de simüle edilebilir.
// 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 getiri türü clone-Funkure şimdi std::unique_ptr<Window>Ve döndürülen nesne bir std::make_unique<Window>(*this) (Satır 1), bir std::make_unique<DefaultWindow>(*this) (Riga 2) OA std::make_unique<FancyWindow>(*this) (Satır 3).
Program çıktısı bir öncekiyle aynı kalır:
Tamlık için, bu örneği biriyle vermek istiyorum std::shared_ptr alet.
std::shared_ptr
Bir dönüş std::shared_ptr Bu, arayan ve paylaşım mülkünün -up adı verdiği anlamına gelir. Ne çağrı ne de bunu aradıysa std::shared_ptr Daha fazlasına ihtiyacınız var, otomatik olarak yok edildi.
// 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';
}
Örneğin taşınması covariantReturnTypeUniquePtr.cpp İçinde covariantReturnTypeSharedPtr.cpp Bu bir çocuk oyunu: sadece değiştiriyorum unique Başından sonuna kadar shared. Beklendiği gibi, bu programın aşağıdaki baskısına dönüşür:
Sırada ne var?
Bir sonraki makalem biraz çizgi değil, çünkü polimorfizm ve modellerle ilgili her şeye zaten yazılmış her şeye genel bir bakış vereceğim.
2023'te açık varlık oluşumum
Dört eğitim kursunun hepsi Aramis Training Hotel'de (Herrenberg) gerçekleşir.
(harita)
Ne yazık ki, bu bağlantı artık geçerli değil.
Boşa harcanan eşyalara olan bağlantılar, 7 günlük daha büyükse veya çok sık çağrılmışsa gerçekleşmez.
Bu makaleyi okumak için bir Haberler+ paketine ihtiyacınız var. Şimdi yükümlülük olmadan bir hafta deneyin – yükümlülük olmadan!
Yazılımın Geliştirilmesinde Idioma: Covariant Return Türü
Bir üye işlevinin Covaric Dönüşü türü, üzerine yazmanın bir üye işlevinin daha dar bir tür döndürmesine izin verir. Bu, özellikle C ++ 'da prototip modelini uygularken önemli bir rol oynar.

Önceki makalelerime daha ayrıntılı olarak açıklamadan Covaric dönüş türünü zaten kullandım. Bugün ulaşacağım.
Tür Kovar dönüşü
Başlangıçta saf bir uygulamayla başlıyorum.
Saf versiyon
Aşağıdaki program covariantReturnType.cpp Prototip modelini kullanın.
// 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 sınıfı Window (Riga 1) sanal bir clone-İşlev. . clone-T işlev kendi bir kopyasını döndürür. Gibi türetilen sınıflar DefaultWindow (Satır 2) e FancyWindow (Satır 3) ayrıca kendisinin bir kopyasını da döndürür. İşlev cloneWindow (Satır 4) sanal üyenin işlevini kullanır ve kullanma klonları oluşturur Window. Ben de bir sanal var getName-Sanal sevkiyatı görüntülemek için uygulandı.
Program çıktısının henüz bir sürprizi yok:

Bu örnekte Covaric Geri Dönüş türünün kullanımı açıkça tanınabilir mi? Sanal clone– Window Bir tane verir Window-Her geri döndü, ama sanal clone– DefaultWindow A DefaultWindow-Pointer ve sanal clone– FancyWindow Süslü bir işaretçi. Bu, veri türünün Kovaryte olduğu anlamına gelir: Bir türev sınıf işlevi, üzerine yazılmış bir temel sınıf işlevine kıyasla başka bir türev türü döndürürse, türev sınıfının geri dönüşü türüne kovaryant denir.
Ayrıca altını çizmek istediğim küçük bir uzmanlık var: sanal üye çalışmasına rağmen clone itibaren DefaultWindow VE FancyWindows Onlar özel, işlev cloneWindow (Riga 4) Sizi arayın. Bunun nedeni basit: üye işlevi cloneWindow Arayüz sınıfının genel arayüzünü kullanın Window.
Ama neden bu uygulama biçimini naif olarak tanımladım?
Mülk
Genel olarak, clone-Funkure bilinmiyor. clone Birine bir işaretçi verir Window Geriye doğru. İşaretçilerin doğası gereği bir kusuru vardır; Tamamen farklı iki semantiği şekillendiriyorlar: mülkiyet ve kredi.
- mülk: Arayan bunun için Window sorumlu ve onu yok etmeli; Bu programın davranış covariantReturnType.cpp modellenmiş.
- Ödünç vermek: Arayan bunun için Window Arayandan sorumlu ve ödünç alınmış.
- Mal sahibi: Sen Window. Onunla ilgilenmeli ve yok etmelisin. Aksi takdirde, bellek kaybına neden olur.
- Sakinlik: Sen Window. Yok edemezsin. Eğer yok ederse, çift iptal neden olur.
std::unique_ptr
Bir dönüş std::unique_ptr Bu, arayanın sahibi olduğu anlamına gelir. . std::unique_ptr Yerel bir değişken gibi davranır. Bu, bölgenizi terk ederse, otomatik olarak yok edilecektir. Covaric geri dönüşü de simüle edilebilir.
// 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 getiri türü clone-Funkure şimdi std::unique_ptr<Window>Ve döndürülen nesne bir std::make_unique<Window>(*this) (Satır 1), bir std::make_unique<DefaultWindow>(*this) (Riga 2) OA std::make_unique<FancyWindow>(*this) (Satır 3).
Program çıktısı bir öncekiyle aynı kalır:

Tamlık için, bu örneği biriyle vermek istiyorum std::shared_ptr alet.
std::shared_ptr
Bir dönüş std::shared_ptr Bu, arayan ve paylaşım mülkünün -up adı verdiği anlamına gelir. Ne çağrı ne de bunu aradıysa std::shared_ptr Daha fazlasına ihtiyacınız var, otomatik olarak yok edildi.
// 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';
}
Örneğin taşınması covariantReturnTypeUniquePtr.cpp İçinde covariantReturnTypeSharedPtr.cpp Bu bir çocuk oyunu: sadece değiştiriyorum unique Başından sonuna kadar shared. Beklendiği gibi, bu programın aşağıdaki baskısına dönüşür:

Sırada ne var?
Bir sonraki makalem biraz çizgi değil, çünkü polimorfizm ve modellerle ilgili her şeye zaten yazılmış her şeye genel bir bakış vereceğim.
2023'te açık varlık oluşumum

Dört eğitim kursunun hepsi Aramis Training Hotel'de (Herrenberg) gerçekleşir.
(harita)
Ne yazık ki, bu bağlantı artık geçerli değil.
Boşa harcanan eşyalara olan bağlantılar, 7 günlük daha büyükse veya çok sık çağrılmışsa gerçekleşmez.
Bu makaleyi okumak için bir Haberler+ paketine ihtiyacınız var. Şimdi yükümlülük olmadan bir hafta deneyin – yükümlülük olmadan!