Fonksiyonların çalışma zamanında içe aktarılmasına izin vermek için bir C ++ programı nasıl tasarlanır?


10

Bugün, size belirli bir yazılım mimarisi gerçekleştirme konusunda C ++ yetenekleri hakkında bir soru sormak istiyorum.

Tabii ki, aramayı kullandım ama doğrudan bağlantılı bir cevap bulamadım.

Temel olarak, amacım kullanıcının keyfi olarak oluşturulmuş fiziksel sistemlerin modellenmesine ve simülasyonuna, örneğin bir arabaya izin veren bir program oluşturmak. Fiziksel modeller (sınıflar içindeki fonksiyonlar) kütüphanesine sahip olduğumu varsayıyorum. Her bir fonksiyon bazı girişlere sahip olabilir ve temel fiziksel açıklamaya bağlı olarak bazı çıkışlar verebilir, örneğin bir yanmalı motor modeli, aerodinamik sürükleme modeli, tekerlek modeli, vb.

Şimdi, fikir kullanıcıya herhangi bir işlevi kendi ihtiyaçlarına göre oluşturmasına, yani herhangi bir fiziksel davranışı haritalamasına izin veren bir çerçeve sağlamaktır. Çerçeve, farklı işlevlerin çıkışlarını ve girişlerini bağlamak için işlevler sağlamalıdır. Bu nedenle, çerçeve bir konteyner sınıfı sağlar. Bir veya daha fazla model nesnesini tutabilen KOMPONENT diyorum (FUNCTION). Bu kaplar ayrıca fonksiyon parametreleri arasındaki bağlantıları (CONNECTOR) yanı sıra diğer bileşenleri de (cf. kompozit modeli) tutabilir. Ek olarak, bileşen sınıfı matematik çözücü gibi genel sayısal işlevler sağlar.

Fonksiyonların bileşimi çalışma zamanı sırasında yapılmalıdır. İlk durumda, kullanıcı, kompozisyon yapısını tanımlayan bir XML'yi içe aktararak bir kompozisyon ayarlayabilmelidir. Daha sonra, bir GUI eklemeyi düşünebiliriz.

Burada size daha iyi bir anlayış sağlamak için çok basitleştirilmiş bir örnek:

<COMPONENT name="Main">
  <COMPONENT name="A">
    <FUNCTION name="A1" path="lib/functionA1" />
  </COMPONENT>
  <COMPONENT name="B">
    <FUNCTION name="B1" path="lib/functionB1" />
    <FUNCTION name="B2" path="lib/functionB2" />
  </COMPONENT>
  <CONNECTIONS>
    <CONNECTOR source="A1" target="B1" />
    <CONNECTOR source="B1" target="B2" />
  </CONNECTIONS>        
</COMPONENT>

Sorunum çok daha genel olduğu için çerçevenin yeteneklerine daha fazla dalmak gerekli değildir. Çerçeve kodu / programı derlendiğinde, kullanıcı tanımlı işlevlerin yanı sıra fiziksel sorun açıklaması da bilinmemektedir. Kullanıcı bir işlevi seçtiğinde (XML aracılığıyla veya daha sonra bir GUI aracılığıyla), çerçeve işlev bilgilerini okumalı, yani kullanıcıya işlevler arasında bağlantı kurma seçeneği sunmak için giriş ve çıkış parametrelerinin bilgilerini almalıdır.

Yansıma ilkelerini biliyorum ve C ++ 'ın bu özelliği sağlamadığının farkındayım. Ancak, "çalışma zamanı sırasında nesneler oluşturma" kavramının sıklıkla gerekli olduğundan eminim. Hedefime ulaşmak için C ++ yazılım yazılımımı nasıl ayarlamalıyım? C ++ doğru dil mi? Neyi gözden kaçırırım?

Şimdiden teşekkürler!

Şerefe, Oliver


C ++ işlev işaretçileri ve işlev nesnelerine sahiptir. Tüm işlevler yürütülebilir dosyada mı derlenmiş veya dinamik kütüphanelerde (hangi platformda)?
Caleth

1
Soru, genellikle elektrik mühendisliği / [elektronik tasarım otomasyonu (EDA)] ( en.wikipedia.org/wiki/Electronic_design_automation ) veya makine mühendisliği / bilgisayar destekli tasarımda (CAD) üniversite derecesi gerektirmesi bakımından çok geniştir . Nispeten konuşursak, C / C ++ dinamik kütüphanesini aramak çok kolaydır, bkz . X86 için C çağırma kuralları . Yine de yığının (CPU yığın işaretçisi aracılığıyla) ve CPU kayıt değerlerinin değiştirilmesini gerektirebilir.
rwong

1
Dinamik olarak yükleme işlevleri C ++ dili tarafından desteklenmez. Platforma özgü bir şeye bakmanız gerekecek. Örneğin, Windows üzerinde bir C ++ derleyicisi bir yansıma biçimini destekleyen Windows DLL'leri desteklemelidir.
Simon B

C ++ 'da, derleme zamanında imzası (bağımsız değişken ve dönüş türleri) bilinmeyen bir işlevi çağırmak gerçekten zordur. Bunu yapmak için, işlev çağrılarının seçtiğiniz platformun montaj düzeyinde nasıl çalıştığını bilmeniz gerekir.
Bart van Ingen Schenau

2
Bunu çözmenin yolu, eval komutunu destekleyen herhangi bir dil için bir yorumlayıcı oluşturan c ++ kodunu derlemektir. Bang sorunu c ++ ile çözüldü. : P Lütfen bunun neden yeterli olmadığını düşünün ve soruyu güncelleyin. Gerçek gereksinimler net olduğunda yardımcı olur.
candied_orange

Yanıtlar:


14

Saf standart C ++ 'da, "işlevlerin çalışma zamanında içe aktarılmasına izin veremezsiniz"; standarda göre, C ++ fonksiyonlarının kümesi, programınızı oluşturan tüm çeviri birimlerinin birleşmesinden sabitlendiğinden, derleme sırasında (uygulamada, bağlantı zamanı) statik olarak bilinir .

Uygulamada, çoğu zaman (gömülü sistemler hariç) C ++ programınız bazı işletim sistemlerinin üzerinde çalışır . İyi bir genel bakış için İşletim Sistemleri: Üç Kolay Parça bölümünü okuyun .

Çeşitli modern işletim sistemleri izin dinamik yükleme ve eklentileri . POSIX özellikle dlopen& karakterini belirtir dlsym. Windows farklı LoadLibrarybir şeye sahiptir (ve daha düşük bir bağlantı modeli; ilgili ekler tarafından sağlanan, sağlanan veya kullanılan işlevlere açıkça açıklama eklemeniz gerekir). BTW Linux üzerinde pratik olarak dlopenbüyük miktarda eklenti ( manydl.cprogramımı görün , yeterli sabırla üretebilir ve yaklaşık bir milyon eklenti yükleyebilirsiniz). Böylece XML nesneniz eklentilerin yüklenmesini sağlayabilir. Çok bileşenli / çok konektörlü açıklamanız bana Qt sinyallerini ve yuvalarını hatırlatıyor ( önişlemci gerektirirmoc ; buna benzer bir şeye ihtiyacınız olabilir).

Çoğu C ++ uygulaması ad yönetimi kullanır . Bu nedenle, extern "C"eklentilerle ilgili işlevler (ve bunlarda tanımlanmış dlsymve ana programdan erişilir) olarak daha iyi beyan edersiniz . C ++ dlopen mini HowTo'yu okuyun (en azından Linux için).

BTW, Qt ve POCO , eklentilere taşınabilir ve daha üst düzey bir yaklaşım sağlayan C ++ çerçeveleridir. Ve libffi , imzası yalnızca çalışma zamanında bilinen işlevleri çağırmanızı sağlar.

Başka bir olasılık da programınıza Lua veya Guile gibi bazı tercümanları yerleştirmektir (veya Emacs'ın yaptığı gibi kendi yorumcunuzu yazmanız). Bu güçlü bir mimari tasarım kararıdır. Daha fazla bilgi için Lisp'i Küçük Parçalar ve Programlama Dili Edimbiliminde okumak isteyebilirsiniz .

Bu yaklaşımların varyantları veya karışımları vardır. Bazı JIT derleme kitaplıklarını kullanabilirsiniz ( libgccjit veya gibi asmjit). Çalışma zamanında geçici bir dosyada bazı C ve C ++ kodları üretebilir , geçici bir eklenti olarak derleyebilir ve bu eklentiyi dinamik olarak yükleyebilirsiniz ( GCC MELT'de böyle bir yaklaşım kullandım ).

Tüm bu yaklaşımlarda, bellek yönetimi önemli bir sorundur ("tüm program" özelliğidir ve programınızın "zarfı" aslında "değişmektedir"). Çöp toplama konusunda en azından biraz kültüre ihtiyacınız olacak . Terminoloji için GC el kitabını okuyun . Birçok durumda (keyfi olarak dairesel referanslar zayıf işaretçileri tahmin edilebilir değildir), bir referans sayım C ++ için şema değerli akıllı işaretçiler yeterli olmayabilir. Ayrıca bkz bu .

Dinamik yazılım güncellemesi ile ilgili bilgileri de okuyun .

Bazı programlama dillerinin, özellikle Common Lisp (ve Smalltalk ), çalışma zamanı içe aktarma işlevlerini daha kolay kullandığına dikkat edin. SBCL , Common Lisp'in ücretsiz bir yazılım uygulamasıdır ve her REPL etkileşiminde makine kodunu derler (ve hatta makine kodunu toplayabilir ve daha sonra kolayca yeniden başlatılabilen tüm çekirdek görüntü dosyasını kaydedebilir ).


3

Açıkçası, kendi simulink veya LabVIEW türü yazılım stilinizi, ancak kutsal olmayan bir XML bileşeniyle yuvarlamaya çalışıyorsunuz.

En temelde, grafik odaklı bir veri yapısı arıyorsunuz. Fiziksel modelleriniz düğümler (bunlara bileşen olarak adlandırılır) ve kenarlardan (adınızdaki konektörler) oluşur.

Bunu yapmak için herhangi bir dil uygulanmış mekanizma yoktur, yansıma olsa bile, bu nedenle bunun yerine bir API oluşturmanız gerekir ve oynatmak isteyen herhangi bir bileşenin birkaç işlevi yerine getirmesi ve API'nız tarafından belirlenen kurallara uyması gerekir.

Her bileşenin aşağıdakileri yapmak için bir dizi işlev uygulaması gerekir:

  • Bileşenin adını veya bileşenle ilgili diğer ayrıntıları edinin
  • Bileşenin kaç tane girdi veya çıktı gösterdiğini öğrenin
  • Bir bileşeni çıktımızdaki belirli bir girdi hakkında sorgula
  • Girişleri ve çıkışları birbirine bağlayın
  • ve diğerleri

Ve bu sadece grafiğinizi ayarlamak için. Modelinizin gerçekte nasıl yürütüldüğünü düzenlemek için tanımlanmış ek işlevlere ihtiyacınız olacaktır. Her işlevin belirli bir adı olur ve tüm bileşenlerin bu işlevleri olması gerekir. Bir bileşene özgü herhangi bir şey, bu API aracılığıyla bileşenden bileşene özdeş bir şekilde erişilebilir olmalıdır.

Programınız bu 'kullanıcı tanımlı işlevleri' çağırmaya çalışmamalıdır. Bunun yerine, her bileşende genel amaçlı bir 'hesaplama' işlevi veya benzeri bir işlev çağırmalıdır ve bileşenin kendisi bu işlevi çağırmayı ve girdisini çıkışına dönüştürmeyi başarır. Giriş ve çıkış bağlantıları bu işlevin soyutlamalarıdır, programın görmesi gereken tek şey budur.

Kısacası, bunun küçük bir kısmı aslında C ++ 'a özgüdür, ancak sorun alanınıza göre uyarlanmış bir tür çalışma zamanı türü bilgisi uygulamanız gerekecektir. API tarafından tanımlanan her işlevle, çalışma zamanında hangi işlev adlarını çağıracağınızı bilirsiniz ve bu çağrıların her birinin veri türlerini bilirsiniz ve bunu yapmak için yalnızca normal eski dinamik kitaplık yüklemesini kullanırsınız. Bu makul miktarda kazan plakasıyla gelecek, ancak bu sadece hayatın bir parçası.

Aklınızda bulundurmanız gereken tek C ++ özel yönü, API'nizin bir C API olması için en iyisidir, böylece kullanıcılar kendi modüllerini sağlıyorsa farklı modüller için farklı derleyiciler kullanabilirsiniz.

DirectShow, açıkladığım her şeyi yapan ve bakmak için iyi bir örnek olabilecek bir API.


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.