簡體   English   中英

我可以在C ++中創建匿名類並捕獲像Java中的外部變量嗎?

[英]Can I create anonymous classes in C++ and capture the outside variables like in Java?

在Java中,當我需要一個回調函數時,我必須實現一個匿名類。 在匿名類中,如果它們是final ,我可以訪問外部變量。

現在我在C ++中做同樣的事情。 我理解C ++ lambda工作得更好但有時候我需要傳入許多帶有匿名類的函數,我只需要傳入一個實例。

我嘗試了以下示例。 它適用於GCC 4.3.4。

class IA {
public:
  virtual int f(int x) = 0;  
};

int main() {
    class : public IA {
        int f(int x) { return x + 1; }
    } a;
    doFancyWork(&a);
    return 0;
}

有可能像這樣捕獲外部變量嗎?

int main() {
    int y = 100; // mark y as final if possible
    class : public IA {
        int f(int x) { return x + y; }
    } a;
    return 0;
}

更新:

第二個例子不會編譯。 錯誤在這里,

prog.cpp: In member function ‘virtual int main()::<anonymous class>::f(int)’:
prog.cpp:9: error: use of ‘auto’ variable from containing function
prog.cpp:7: error:   ‘int y’ declared here
prog.cpp: In function ‘int main()’:
prog.cpp:7: warning: unused variable ‘y’

更新:

我剛剛意識到這樣做的一些問題:

  • 我無法編寫構造函數,因為該類沒有名稱
  • 初始化列表不允許繼承。
  • 任何使其編譯的更改都會使代碼無法讀取。

我想我必須離開匿名課程。

無法自動捕獲這些變量,但您可以使用其他方法。 如果您想通過引用捕獲:

int main() {
    int y = 100; // mark y as final if possible
    class IB : public IA {
    public:
      IB(int& y) : _y(y) {}
      int f(int x) { return x + _y; }
    private:
      int& _y;
    } a (y);
    return 0;
}

如果要按值捕獲,只需將int&更改為int

無論如何,你可以考慮使用lambdas元組作為“多回調”對象,如果這是困擾你的個別lambdas。 您仍然可以將所有內容打包在一個對象中,並且可以免費進行捕獲。

舉個例子:

auto callbacks = make_tuple(
    [] (int x) { cout << x << endl; },
    [&] () { cout << y << endl; }, // y is captured by reference
    [=] (int x) { cout << x + y << endl; }, // y is captured by value
    // other lambdas here, if you want...
    );

您可以手動捕獲變量(類似於lambda捕獲在幕后執行的操作):

int main() {
    int y = 100;
    struct { 
        int& y;
        int operator()(int x) { return x + y; }
    } anon = { y };
}

然后你可以像這樣使用它:

#include <iostream>
...
std::cout << anon(10) << std::endl;

按預期打印110。 不幸的是,您不能使用此方法從另一個繼承匿名類型,因為初始化列表可構造類型不能從其他類型繼承。 如果繼承是至關重要的,那么你應該使用Andy Prowl概述構造函數方法

C ++ lambda可以捕獲“外部”變量。 [編輯:當我第一次看到這個問題時,我不知何故錯過了他提到他知道lambdas的地方。 無論好壞,C ++沒有任何其他真正類似於匿名類的東西]。

例如:

#include <iostream>

int main(){ 

    int y = 100;
    auto lambda = [=](int x) { return x + y; };

    std::cout << lambda(2);
}

...打印102作為其輸出。

請注意,盡管它看起來有點像函數,但C ++ lambda確實會導致創建一個類。 我想我應該補充一點:該類在技術上並不是匿名的,但它有一些從未直接可見的未指定名稱。

編輯:我仍然有點不知道不使用lambdas的理由。 是否意圖使用包含許多成員函數的一個類? 如果是這樣,則不清楚您計划如何指定在哪個時間/為何目的調用哪個成員函數。 我的直接反應是,這聽起來很可疑,好像你試圖扭曲語言來支持有問題的設計。

限制訪問外部變量的類的匿名性不是。 在問題中,y不可訪問,因為該類是在函數內本地定義的。

對本地定義的類有一些限制。 首先,它們只能訪問靜態的局部變量,但可以訪問該函數范圍內可用的任何其他變量。 此外,本地類不能擁有靜態數據成員。

對於匿名類,您不能擁有構造函數或析構函數。 必須在類定義中聲明所有成員函數。 它不能有靜態靜態成員,這包括通常可以在類定義中實例化的const靜態整數成員。 也不允許繼承。

匿名類是C ++的一個不起眼的角落,幾乎沒有實際價值。 Lambda函數和其他技術更加靈活。 但誰知道,也許在某些情況下它可以幫助提高代碼的可讀性。

如果你的IA類真的只有一個你需要覆蓋的虛方法(而真正的復雜性是其他非虛方法),但是你不想捕獲這個方法需要的局部變量,那么:

int main() {
  int y = 100;
  auto f = [=](int x){return x+y;};
  typedef decltype(f) F;
  struct IB : IA {
    F _f;
    IB(F _f): _f(_f) {}
    int f(int x) { return _f(x); }
  } a(f);
  doFancyWork(&a);
  return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM