类成员函数作为函数参数/回调函数 出现error C3867

本文探讨了在C++中使用类成员函数作为模板泛型函数参数时遇到的errorC3867错误,并提供了详细的解决方案。通过定义适配器类,可以成功地将成员函数转换为符合模板要求的形式。

转自:https://blog.youkuaiyun.com/liyunxin_c_language/article/details/83188176

 

类成员函数作为函数参数出现error C3867:非标准语法;请使用“&”来创建指向成员的指针

有的时候一个泛函可能会采用函数或函数对象(functor)做参数,这时候我们可能想要使用类的成员函数来做参数,但是这时候会出现error C3867: 非标准语法;请使用 "&" 来创建指向成员的指针,比如下面例子:

 

  1.  
    #include <iostream>
  2.  
    using namespace std;
  3.  
    class TestC
  4.  
    {
  5.  
    private:
  6.  
    double a, b;
  7.  
    public:
  8.  
    TestC( double a_,double b_):a(a_),b(b_){}
  9.  
    double testFun(double x);
  10.  
    };
  11.  
    template<class Func>
  12.  
    double testTemplateFun(double input, Func proccess)
  13.  
    {
  14.  
    return proccess(input);
  15.  
    }
  16.  
     
  17.  
    int main()
  18.  
    {
  19.  
    double a = 10;
  20.  
    TestC t(2, 3);
  21.  
    cout << "输出结果为:" << testTemplateFun(a, t.testFun);
  22.  
    system( "pause");
  23.  
    return 0;
  24.  
    }
  25.  
     
  26.  
    double TestC::testFun(double x)
  27.  
    {
  28.  
    return a*x + b;
  29.  
    }


这时候我们按照提示将t.testFun前面加上&又会出现error C2276: “&”: 绑定成员函数表达式上的非法操作,那么这到底是什么错误?

其实这里是因为类的成员函数默认带有一个this指针参数,那么它作为泛函的参数其实就不匹配了,因为泛函中的Func类型并没有this指针,所以我们可以把TestC类中的testFun(double x)函数声明为静态(static)的,这样就不带有this指针;但是静态的函数又不能访问非静态的成员,像这里TestC的testFun函数访问了非静态的成员变量a,b,就会出错,那要怎么办?这里其实就是相当于泛函中要求单参函数,而使用的是双参函数,可以自己定义一个适配类,适配双参函数为单参,如下例:

  1.  
    #include <iostream>
  2.  
    using namespace std;
  3.  
    class TestC
  4.  
    {
  5.  
    private:
  6.  
    double a, b;
  7.  
    public:
  8.  
    TestC( double a_,double b_):a(a_),b(b_){}
  9.  
    double testFun(double x);
  10.  
    };
  11.  
    template<class Func>
  12.  
    double testTemplateFun(double input, Func proccess)
  13.  
    {
  14.  
    return proccess(input);
  15.  
    }
  16.  
    class TestCAdapter
  17.  
    {
  18.  
    private:
  19.  
    TestC *t;
  20.  
    public:
  21.  
    TestCAdapter(TestC *t_):t(t_){}
  22.  
    double operator()(double x);
  23.  
    };
  24.  
    int main()
  25.  
    {
  26.  
    double a = 10;
  27.  
    TestC t(2, 3);
  28.  
    //cout << "输出结果为:" << testTemplateFun(a, t.testFun) << endl;
  29.  
    TestCAdapter ad(&t);
  30.  
    cout << "输出结果为:" << testTemplateFun(a, ad) << endl;
  31.  
    system( "pause");
  32.  
    return 0;
  33.  
    }
  34.  
     
  35.  
    double TestC::testFun(double x)
  36.  
    {
  37.  
    return a*x + b;
  38.  
    }
  39.  
     
  40.  
    double TestCAdapter::operator()(double x)
  41.  
    {
  42.  
    return t->testFun(x);
  43.  
    }

转载于:https://www.cnblogs.com/damoying/p/10683244.html

<think>首先,用户在问如何在C++中通过引用传参,并在函数内部调用该参数类的受保护成员函数。关键点是:引用传参、调用受保护的成员函数。 从系统指令中,我需要使用正确的LaTeX格式:行内数学表达式用$...$,独立公式用$$...$$。回答必须用中文,结构清晰,逐步解决问题。最后,生成相关问题。 参考了站内引用: - 引用[1]:解释了C++成员函数的访问权限。私有成员函数只能被本类中的其他成员函数调用,不能类外调用。成员函数可以访问本类中任何成员(包括私有和公有)。 - 引用[2]:展示了如何将类的成员函数封装成函数对象并调用,使用std::bind。对于非静态成员函数,需要对象实例;对于静态成员函数,不需要。 - 引用[3]:重申了访问修饰符:private、protected、public的作用范围。 - 引用[4]:关于Java调用C++库的回调,但似乎不直接相关。 用户的问题是:如何在函数内部调用参数类的受保护成员函数?参数是通过引用传递的。 核心问题:受保护成员函数(protected member function)只能在类内部或派生类中访问。不能在类外部直接访问,除非通过友元或继承机制。 所以,解决方案可能涉及: 1. 让函数成为该类的友元函数(friend function),这样它就可以访问受保护成员。 2. 或者,让函数属于该类的派生类,这样在派生类中可以访问基类的受保护成员。 用户指定了“引用传参”,所以参数是通过引用传递的类对象。 步骤: - 定义一个类,其中包含受保护的成员函数。 - 定义一个外部函数,该函数通过引用接受这个类的对象。 - 在这个外部函数中,调用对象中的受保护成员函数。 但直接调用会失败,因为外部函数没有访问受保护成员的权限。 因此,需要一种方式授予访问权限。 方法1:使用友元函数。 - 在类声明中,声明外部函数为友元。 - 这样,外部函数就可以访问类的所有成员,包括受保护成员。 方法2:使用继承。 - 创建一个派生类,继承自基类。 - 在派生类中,定义一个成员函数来调用基类的受保护成员函数。 - 然后,外部函数可以通过派生类对象来调用这个成员函数。 用户提到“参数类的受保护成员函数”,意思是参数是某个类的对象,我们需要调用该类的受保护成员函数。 所以,在外部函数中,参数是基类引用。 如果使用继承方法,外部函数可能需要接受派生类引用,但用户指定了“参数类”,可能指的是基类。 为了通用性,最好使用友元方法。 代码示例: 假设我们有一个类Base,其中有一个受保护的成员函数protFunc()。 我们想定义一个外部函数externalFunc,它通过引用接受Base对象,并调用protFunc()。 使用友元: ```cpp class Base { protected: void protFunc() { // 实现受保护函数 } // 声明外部函数为友元 friend void externalFunc(Base& obj); }; void externalFunc(Base& obj) { obj.protFunc(); // 现在可以访问,因为是友元 } ``` 这样,externalFunc就可以通过引用obj调用protFunc。 如果不使用友元,另一种方式是: - 在Base类中,提供一个公有成员函数来调用受保护函数,但用户可能不想修改类,或者受保护函数需要直接调用。 用户问题中,没有指定类是否可修改,所以提供友元方法是直接的。 现在,关于引用传参:externalFunc(Base& obj) 使用引用,避免了复制,并允许修改对象(如果protFunc修改对象状态)。 在回答中,我需要结构清晰: 1. 解释问题:受保护成员函数只能在类内部或派生类访问。 2. 提出解决方案:使用友元函数。 3. 给出代码示例。 4. 讨论其他方法,如继承。 最后,生成相关问题。 确保LaTeX正确:在这个上下文中,可能没有数学表达式,但如果有,比如讨论访问权限时,可以用行内格式。 例如,访问权限如 $private$, $protected$, $public$。 但这里可能不需要。 回答结构: - 引言:重述问题。 - 解决方案:逐步解释。 - 代码示例。 - 注意事项。 - 相关问题。 用中文回答。</think>### 在C++中通过引用传参并调用参数类的受保护成员函数 在C++中,调用一个类的受保护成员函数(protected member function)通常受限于类内部或派生类访问[^1]。如果需要在外部函数中通过引用传参来调用参数对象的受保护成员函数,必须解决访问权限问题。核心方法是使用 **友元函数(friend function)** 或 **继承机制**,以下我将逐步解释解决方案。假设参数类为 `MyClass`,其中包含受保护的成员函数 `protectedFunc()`。 #### 步骤1: 理解问题 - **受保护成员函数**:只能被本类、派生类或友元访问,外部函数直接调用会编译错误[^1][^3]。 - **引用传参**:使用 `MyClass& obj` 传递对象引用,避免复制开销,并允许函数修改对象状态。 - 目标:在外部函数 `externalFunction(MyClass& obj)` 中调用 `obj.protectedFunc()`。 #### 步骤2: 推荐解决方案(使用友元函数) 最直接的方式是将外部函数声明为参数类的友元(friend),这样它就能访问所有受保护和私有成员[^1][^3]。以下是完整代码示例: ```cpp #include <iostream> // 定义参数类 class MyClass { protected: // 受保护成员函数 void protectedFunc() { std::cout << "受保护函数被调用!" << std::endl; } public: // 声明外部函数为友元,授予访问权限 friend void externalFunction(MyClass& obj); }; // 外部函数,通过引用接受 MyClass 对象 void externalFunction(MyClass& obj) { // 现在可以直接调用受保护成员函数 obj.protectedFunc(); } int main() { MyClass obj; externalFunction(obj); // 通过引用传参调用 return 0; } ``` **关键点解释**: - **友元声明**:在 `MyClass` 中,`friend void externalFunction(MyClass& obj);` 允许 `externalFunction` 访问 `protectedFunc()`,即使它是外部函数[^1]。 - **引用传参**:`externalFunction(MyClass& obj)` 使用引用,确保高效传递对象(避免复制)并支持修改对象内部状态。 - **编译与运行**:此代码能正确编译和执行,输出 "受保护函数被调用!"。 #### 步骤3: 替代解决方案(使用继承) 如果无法修改参数类(如它是第三方库中的类),可以通过派生类间接访问受保护成员。派生类能访问基类的受保护成员,然后提供一个公有接口供外部函数调用[^3]。 ```cpp #include <iostream> // 基类(假设这是参数类) class MyBaseClass { protected: void protectedFunc() { std::cout << "受保护函数被调用!" << std::endl; } }; // 创建派生类 class MyDerivedClass : public MyBaseClass { public: // 公有成员函数,调用基类的受保护函数 void callProtected() { protectedFunc(); // 派生类内部可访问 } }; // 外部函数,通过引用接受派生类对象 void externalFunction(MyDerivedClass& obj) { obj.callProtected(); // 间接调用受保护函数 } int main() { MyDerivedClass obj; externalFunction(obj); // 通过引用传参 return 0; } ``` **关键点解释**: - **派生类作用**:`MyDerivedClass` 继承自 `MyBaseClass`,并在公有函数 `callProtected()` 中调用 `protectedFunc()`,从而绕过访问限制。 - **引用传参**:外部函数 `externalFunction` 接受派生类引用,但需注意:这要求外部函数使用派生类类型,而非基类(如果参数必须是基类引用,此方法不适用)。 - **适用场景**:当参数类不可修改时(例如,外部库中的类),此方法更灵活。 #### 注意事项 1. **访问权限**:受保护成员只能在特定上下文中访问,直接外部调用会导致编译错误(如 `error: 'void MyClass::protectedFunc()' is protected`)[^1][^3]。 2. **引用 vs 指针**:引用传参(`MyClass&`)更安全(避免空指针),但如果需要动态绑定,可使用指针(如 `MyClass*`)。 3. **性能**:引用传参无额外开销,适合大型对象。 4. **设计考虑**:过度使用友元可能破坏封装性,建议仅在必要时使用。如果参数类设计良好,应提供公有接口来间接访问受保护成员[^1]。 #### 相关问题 1. 如何在C++中通过指针传参并调用私有成员函数? 2. C++友元函数的优缺点是什么? 3. 派生类如何访问基类的私有成员? 4. 在回调函数中如何安全地调用受保护成员函数(参考引用[2][^4])?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值