C ++ 'da her şey için nesneleri (ilkel türler yerine) kullanmak anlamlı olur mu?


17

Üzerinde çalıştığım yeni bir proje sırasında, şöyle görünen bir çok işlevi kullanmak zorunda kaldım:

static bool getGPS(double plane_latitude, double plane_longitude, double plane_altitude,
                       double plane_roll, double plane_pitch, double plane_heading,
                       double gimbal_roll, double gimbal_pitch, double gimbal_yaw, 
                       int target_x, int target_y, double zoom,
                       int image_width_pixels, int image_height_pixels,
                       double & Target_Latitude, double & Target_Longitude, double & Target_Height);

Bu yüzden böyle bir şey bakmak için refactor istiyorum:

static GPSCoordinate getGPS(GPSCoordinate plane, Angle3D planeAngle, Angle3D gimbalAngle,
                            PixelCoordinate target, ZoomLevel zoom, PixelSize imageSize)

Bu bana ilk yönteme göre önemli ölçüde daha okunaklı ve güvenli gözüküyor. Ama yaratmak PixelCoordinateve PixelSizesınıflamak mantıklı mı? Yoksa sadece std::pair<int,int>her biri için kullanmak daha iyi olurdu . Ve bir ZoomLevelsınıfa sahip olmak anlamlı mı yoksa sadece a doublemı kullanmalıyım ?

Sınıfları her şey için kullanmanın ardındaki sezgilerim bu varsayımlara dayanıyor:

  1. Her şey için sınıflar varsa, ZoomLevelbir Weightnesnenin beklendiği yere geçmek imkansızdır , bu nedenle bir işleve yanlış argümanlar sağlamak daha zor olurdu
  2. Benzer şekilde, bazı yasadışı işlemler, GPSCoordinatea ZoomLevelveya başka bir karaktere ekleme gibi derleme hatalarına neden olabilir.GPSCoordinate
  3. Yasal işlemlerin temsil edilmesi ve yazımı kolay olacaktır. yani iki saniyenin çıkarılması GPSCoordinate,GPSDisplacement

Ancak, gördüğüm çoğu C ++ kodu çok ilkel türleri kullanır ve bunun için iyi bir neden olması gerektiğini hayal ediyorum. Nesneleri herhangi bir şey için kullanmak iyi bir fikir mi, yoksa farkında olmadığım dezavantajları var mı?


8
"Gördüğüm çoğu C ++ kodu çok sayıda ilkel tür kullanıyor" - iki düşünce akla geliyor: C ++ kodu çok zayıf soyutlama olan C aşina programcılar tarafından yazılmış olabilir; Ayrıca Sturgeon Yasası
congusbongus

3
Bence ilkel tipler basit, anlaşılır, hızlı, şık ve verimlidir. Şimdi OP örneğinde, bazı yeni sınıfları tanıtmak kesinlikle iyi bir fikirdir. Ama başlık sorusunun cevabı (burada "her şey" yazıyor) kocaman bir hayır!
Bay Lister

1
@Max çiftleri yazmak OP sorununu çözmek için kesinlikle hiçbir şey yapmaz.
Bay Lister

1
@CongXu: Neredeyse aynı düşünceye sahiptim, ama daha çok "herhangi bir dilde çok fazla kod, soyutlamalar oluşturmada sorun yaşayan programcılar tarafından yazılmış olabilir".
Doc Brown

1
Demişler "17 parametreli bir fonksiyonunuz varsa, muhtemelen birkaçını kaçırdınız".
Joris Timmermans

Yanıtlar:


24

Evet kesinlikle. Çok fazla argüman alan işlevler / yöntemler bir kod kokusudur ve aşağıdakilerden en az birini gösterir:

  1. İşlev / yöntem aynı anda çok fazla şey yapıyor
  2. İşlev / yöntem o kadar çok şeye erişmeyi gerektirir çünkü bazı OO tasarım yasasını sormaz, söylemez veya ihlal etmez
  3. Argümanlar aslında yakından ilişkilidir

Sonuncusu ise (ve örneğiniz kesinlikle bunu gösteriyorsa), havalı çocukların oh, sadece birkaç on yıl önce konuştuğunu bu fantezi pantolon "soyutlama" nın bazılarını yapmanın tam zamanı . Aslında, senin örnek daha ileri gitmek ve gibi bir şey yapmak:

static GPSCoordinate getGPS(Plane plane, Angle3D gimbalAngle, GPSView view)

(GPS'e aşina değilim, bu yüzden muhtemelen doğru bir soyutlama değildir; örneğin, zoom'un adı verilen bir işlevle ne yapması gerektiğini anlamıyorum getGPS.)

İkisi aynı verilere sahip olsa bile, lütfen PixelCoordinateüstü gibi sınıfları tercih std::pair<T, T>edin. Anlamsal değer ve biraz ekstra tip güvenlik ekler (derleyici her ikisi de s olsa bile bir ScreenCoordinatea geçmesini engelleyecektir .PixelCoordinatepair


1
bahsetmiyorum, tüm serin çocuklar yapmaya çalışıyorum ama gerçekten olmamalı biraz mikro-optimizasyon biraz referans için daha büyük yapıları geçebilirsiniz
cırcır ucube

6

Yasal Uyarı: C + C ++ tercih ederim

Sınıflar yerine yapıları kullanırdım. Bu nokta en iyi şekilde bilgiçtir, çünkü yapılar ve sınıflar neredeyse aynıdır ( basit bir grafik veya bu SO sorusu için buraya bakınız ), ancak bence farklılaşmada değer vardır.

C programcıları, gruplandıklarında daha büyük bir anlamı olan veri blokları olarak yapılara aşinayken, bir clasas gördüğümde, bu durumu manipüle etmek için bazı iç durum ve yöntemler olduğunu varsayıyorum. GPS koordinatının durumu yoktur, yalnızca veri vardır.

Sorunuzdan, bu tam olarak aradığınız şey, genel bir kap, durumsal bir yapı değil gibi görünüyor. Diğerlerinin de belirttiği gibi, Zoom'u kendi sınıfına sokmaktan rahatsız olmazdım; Bir veri türüne sahip olmak için oluşturulmuş sınıflardan kişisel olarak nefret ediyorum (profesörlerim yaratmayı Heightve Idsınıfları sever ).

Her şey için sınıflar varsa, bir WeightLevel'i bir Weight nesnesinin beklendiği yere geçirmek imkansızdır, bu nedenle bir işleve yanlış argümanlar sağlamak daha zor olurdu

Bunun bir sorun olduğunu düşünmüyorum. Yaptığınız gibi bariz şeyleri gruplandırarak parametre sayısını azaltırsanız, bu sorunları önlemek için başlıklar yeterli olmalıdır. Gerçekten endişeleniyorsanız, ilkeleri, yaygın hatalar için derleme hataları vermesi gereken bir yapı ile ayırın. İki parametreyi yan yana değiştirmek kolaydır, ancak birbirlerinden daha uzak olmaları daha zordur.

Benzer şekilde, bazı yasadışı işlemler ZoomLevel'e veya başka bir GPSCoordinate'e GPSCoordinate eklemek gibi derleme hatalarına neden olabilir.

Aşırı operatör yükü kullanımı.

Yasal işlemlerin temsil edilmesi ve yazımı kolay olacaktır. yani iki GPSKoordinatının çıkarılması bir GPSDisplacement sağlar

Ayrıca operatör aşırı yüklerinin iyi kullanımı.

Bence doğru yoldasın. Dikkate alınması gereken başka bir şey, bunun programın geri kalanına nasıl uyduğudur.


3

Özel türler kullanmanın avantajları, argümanların sırasını bozmanın çok daha zor olmasıdır. Örnek işlevinizin ilk sürümü, örneğin, 9 çift kişilik bir zincirle başlar. Birisi bu işlevi kullandığında, siparişin vidalanması ve gimbal açılarının GPS koordinatları yerine geçmesi çok kolaydır. Bu çok garip ve izleri zor olabilir. Bunun yerine farklı türlerle yalnızca üç bağımsız değişken ilettiğinizde, bu hata derleyici tarafından yakalanabilir.

Aslında bir adım daha ileri gitmeyi ve teknik olarak özdeş fakat farklı bir anlamsal anlamı olan türleri tanıtmayı düşünürdüm. Örneğin bir sınıfa sahip olmakPlaneAngle3d ve ayrıGimbalAngle3d olmakla birlikte, her ikisi de üç kişilik bir koleksiyon olsa da. Bu, kasıtlı olmadıkça birini diğeri olarak kullanmayı imkansız hale getirir.

typedef double ZoomLevelSadece bu nedenle değil, başka bir şey için de ilkel tipler ( ) için takma adlar olan typedef'lerin kullanılmasını öneriyorum : Türü daha sonra kolayca değiştirmenize izin verir. Bir gün kullanımın daha floatiyi ve doubledaha fazla bellek ve CPU verimli olabileceği fikrini aldığınızda , bunu tek bir yerde değiştirmeniz gerekir, düzineler halinde değil.


Typedef öneri için +1. İlkel tipler ve nesneler: Her iki dünyanın da en iyisini sunar.
Karl Bielefeldt

Bir sınıf üyesinin türünü değiştirmek bir typedef'den daha zor değildir; ya da ilkellere kıyasla mı demek istediniz?
MaHuJa

2

Güzel cevaplar zaten burada, ama eklemek istediğim bir şey var:

PixelCoordinateVe PixelSizesınıf kullanmak işleri çok özel kılar. Bir general Coordinateveya Point2Dsınıf muhtemelen ihtiyaçlarınıza daha iyi cevap verebilir. A Point2D, en yaygın nokta / vektör işlemlerini uygulayan bir sınıf olmalıdır. Böyle bir sınıfı genel olarak bile uygulayabilirsiniz ( Point2D<T>T olabilir intveyadouble veya başka bir şey).

2B nokta / vektör işlemleri çok sayıda 2B geometri programlama görevi için o kadar yaygındır ki, deneyimlerime göre böyle bir karar mevcut 2B işlemlerini yeniden kullanma şansını büyük ölçüde artıracaktır. Her için yeniden uygulama gereğini önleyecektir PixelCoordinate, GPSCoordinate"whatsover" -Coordinate sınıf tekrar tekrar.


1
struct PixelCoordinate:Point2D<int>uygun tip güvenlik istiyorsanız da yapabilirsiniz
cırcır ucube

0

Bu yüzden böyle bir şey bakmak için refactor istiyorum:

static GPSCoordinate getGPS(GPSCoordinate plane, Angle3D planeAngle, Angle3D gimbalAngle,
                        PixelCoordinate target, ZoomLevel zoom, PixelSize imageSize)

Bu bana ilk yönteme göre önemli ölçüde daha okunaklı ve güvenli gözüküyor.

[Daha okunabilir]. Aynı zamanda iyi bir fikir.

Ancak PixelCoordinate ve PixelSize sınıfları oluşturmak mantıklı mı?

Farklı kavramları temsil ediyorlarsa, mantıklıdır (yani "evet").

Yoksa sadece her biri için std :: pair kullanarak daha iyi olurdu.

Yaparak başlayabilirsin typedef std::pair<int,int> PixelCoordinate, PixelSize; . Bu şekilde, anlambilimi (istemci kodunuzdaki std :: çiftleri ile değil, piksel koordinatları ve piksel boyutları ile çalışıyorsunuz) kapsarsınız ve genişletmeniz gerekirse, typedef'i bir sınıfla değiştirirsiniz ve istemci kodunuz minimum değişiklik gerektirir.

Ve bir ZoomLevel sınıfına sahip olmak anlamlı mı yoksa sadece bir double mı kullanmalıyım?

Siz de typedef olabilir, ama ben doubleonunla ilişkili bir işlevsellik ihtiyacım olana kadar bir çift için var olmaz (örneğin, bir ZoomLevel::defaultdeğere sahip bir sınıf tanımlamanız gerekir, ama bir şey var kadar bunu iki katına çıkar).

Sınıfları her şey için kullanmanın ardındaki sezgilerim bu varsayımlara dayanıyor [kısalık için atlanmış]

Bunlar güçlü argümanlardır (her zaman arayüzlerinizin doğru kullanımını ve yanlış kullanımı zor hale getirmeye çalışmalısınız).

Ancak, gördüğüm çoğu C ++ kodu çok ilkel türleri kullanır ve bunun için iyi bir neden olması gerektiğini hayal ediyorum.

Sebepleri var; birçok durumda, bu nedenler iyi değildir. Bunu yapmanın geçerli bir nedeni performans olabilir, ancak bu, bu tür bir kodu kural olarak değil, bir istisna olarak görmeniz gerektiği anlamına gelir.

Nesneleri herhangi bir şey için kullanmak iyi bir fikir mi, yoksa farkında olmadığım dezavantajları var mı?

Değerleriniz her zaman birlikte görünüyorsa (ve hiçbir anlam ifade etmiyorsa) bunları birlikte gruplandırmanız gerektiğinden emin olmak iyi bir fikirdir (postanızda belirttiğiniz aynı nedenlerle).

Yani, her zaman x, y ve z olan koordinatlara sahipseniz, bir coordinatesınıfa sahip olmak, her yere üç parametre iletmekten çok daha iyidir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.