當你用%extend
擴展一個類時,你不能真的添加任何新的成員變量,只有成員函數。如果你在%extend
中這樣做,它將假設存在一個get/set函數。
其原因是新成員變量的存儲(即內存)將不得不在某個地方居住,但沒有明顯的安全位置。你不能修改原來的C++ class
,因爲如果你這樣做的話,當其他一些預編譯的代碼使用該類的舊定義時,最終會導致未定義的行爲;沒有辦法追溯應用新的定義。您無法將其放入以目標語言生成的代理中,因爲在目標語言中C++類和代理之間沒有1:1映射。 (考慮兩個函數,這兩個函數都可以通過指針返回同一個全局實例,以瞭解可能發生這種情況的簡單示例)。
如果你想實現get/set函數來做一些有用的事情(例如,在這裏我使用全局地圖來存儲額外的數據),你不想在%extend
裏實現它們。例如,給出test.hh和只是 - :
%module test
%include "test.hh"
%{
#include "test.hh"
%}
%{
#include <map>
static std::map<Foo<int>*, double> extra_stuff;
const double& Foo_Sl_int_Sg__x_get(Foo<int>* f) {
return extra_stuff[f];
}
void Foo_Sl_int_Sg__x_set(Foo<int>* f, const double& d) {
extra_stuff[f] = d;
}
%}
%template(FooInt) Foo<int>;
%extend Foo<int> {
double x;
}
template <typename T>
struct Foo {};
可以使用std::map
做你想做什麼寫你自己的獲取和設置在包裝免費功能%{ %}
只是徑直通過代碼
ge由於它是一個模板,t/set函數被SWIG自己的mangling系統破壞。我只是看着生成的包裝類,看看他們被稱爲。 (我認爲可能有更聰明的做法,但我無法從文檔中找出它)。如果它不是模板,那麼函數的名稱就會簡單得多。
請注意,此處沒有規定從此地圖刪除條目 - 它只會無限增長。 (你可以通過提供一個在對象生命週期結束時調用額外函數的類型映射來解決這個問題)。你還需要小心線程。
既然你沒有指定你使用的是什麼語言我測試與Java上面的代碼:
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
FooInt f = new FooInt();
f.setX(0.1);
System.out.println(f.getX());
}
}
或者,如果你真的想你可以編寫代碼,以確保有一個獨特的單代理實例在目標語言中,通過編寫一個類型映射來檢查代理是否已經被創建,而不是始終創建一個代理,但是這會引發引用計數和線程安全問題,這些問題很難有效且一般地解決,這就是爲什麼它不是默認行爲。
很多情況下(例如目標語言的迭代器)的最簡單的解決方法是使用%inline
來聲明和定義並全部包含一個全新的額外類,它提供了您想要的功能。
與我的回答無關,但是'myclass * f'的意思是這裏像是一個'this'指針嗎?你不需要明確地寫出這個參數,但是你需要使用'$ self'而不是'this'來加上'%extend'。 – Flexo
是的,這基本上是我試圖使用它。我認爲這種格式是使用'$ self'而不是'this'的替代方案。也許我不能這樣做。 – thebigdog