无法将参数:_cdecl*转换为_thiscall*解决办法

敲黑板重点!!

(Ⅰ)普通的C函数和类中的static函数以_cdecl方式编译,这种方式编译属于普通函数指针
(Ⅱ)类中的成员函数(非static)以_thiscall方式编译,这种编译方式属于成员函数指针
(Ⅲ)这两种函数指针不能由编译器自动转换,(好比你short间接转换成为int允许,但是double到char*就是不行),而且是不能互相自动转换的
(Ⅳ)成员函数指针只能赋值给成员函数指针,普通函数指针只能赋值给普通函数指针

“C++成员函数指针”和“普通函数指针” 具体的语法区别可以直接到目录的"五"那里看。

一,原来的编译报错的代码

这是我快排的一段程序,所有函数都是static,无关的函数体我直接删掉了,最主要就是看主函数的那里就行
排序函数声明

#pragma once
#include <iostream>
using std::swap;
class Qsort {
public:
	static void qsort(int* a, int n) {
		qsort(a, 0, n - 1);
	}
};

主函数

#include <iostream>
#include <cstdlib>
#include <ctime>
#include "Sort.h"
const int MAX = 1000;
int* q = new int[MAX];
void sort(int* a, int n,  void(Qsort::* pf)(int*, int)) {
    pf(a, n);//以_thiscall方式编译的函数指针不能直接调用,因此这行也会编译报错,需要对象调用才行!!!
}
void random(int* a, int n) {
    srand(time(NULL));
    for (int i = 0; i < n; i++) {
        *a++ = rand();
    }
}
int main()
{
    random(q, MAX);
    void (*pf)(int*, int) = Qsort::qsort;
    sort(q, MAX, pf);
    for (int i = 0; i < 100; i++) {
        std::cout << q[i] << "\n";
    }
    delete[] q;
}

二,编译报错:无法将参数:void(_cdecl*)(int*,int)转换为void(_thiscall*)(Qsort::⭐)(int*,int))

在这里插入图片描述

报错无法从void (_cdecl*)(int*,int)到void (_thiscall*)(int*,int)原因分析:

我头文件声明public的static void qsort(int*,int),是一个静态的类函数,可以脱离于对象而存在
然后这种函数就是以 " _cdecl " 的方式进行编译(普通C函数那样编译)

然而,我的sort函数第三个却声明了一个成员函数指针类型的形参,以"_thiscall"方式编译
实参从_cdecl到_thiscall转换失败,因为这种转换本身就非常离谱!!因此编译器马上给你这个编译错误!!

三,解决办法:

就是直接使得他们函数指针类型匹配就行,
_cdecl的函数指针就传到_cdecl的形参里面,默认的C函数调用方式就是直接用。
_thiscall的函数指针就传到_thiscall的形参里面,再以对象调用的方式来调用这个函数。

不要以不同类型的编译方式传参就行,传相同类型的函数指针即可。
下面是我以"_thiscall"方式来调用该函数(稍微改了一下之前的代码)

在这里插入图片描述

四,_thiscall与_cdecl

_cdecl是C语言默认的函数调用方式,更详细的参见百度百科的_cdecl解释。
_thiscall就是对象调用函数的方式,函数参数从右往左入栈,最后编译时增加一个形参,传入一个this指针

五,函数指针的声明

(Ⅰ)_cdecl函数指针的声明:

下面把一个普通的函数赋值给普通函数指针,完全没问题

void print(){
	std::cout<<"HelloWorld!!\n";
}
void (*f)()=&print;//普通函数指针的初始化,_cdecl方式编译

(Ⅱ)_thiscall函数指针的声明

把一个实例对象的一个函数名赋值给一个成员函数指针,完全没有问题

void print(){
	std::cout<<"HelloWorld!!\n";
}
class Foo{
	public:
		void fun(){std::cout<<"Hello\n";}
}
int main(){
	void (Foo::*pf)()=Foo::fun;//普通函数指针声明前加上 "类名::" 就是成员函数指针的声明了,_thiscall 方式编译
	Foo* pObj=new Foo;
	(pObj->*pf)();
}

输出结果就是Hello\n
在这里插入图片描述

(Ⅲ)这样混合赋值就会编译报错

class Foo{
	public:
		static void f_1(){}
		void f_2(){}
}
int main(){
	void (*pf_1)()=&Foo::f_2;//实例的函数赋值给普通函数指针,不同类型的函数指针不能互相赋值,必然编译报错
	void (Foo::*pf_2)()=&Foo::f_1;//把静态的函数赋值给成员函数指针,不同类型的函数指针不能互相赋值,必然报错
}

(Ⅳ)成员函数指针的语法小细节

另外要注意:成员函数指针初始化的时候必须要强制用==&类名::函数名称==来初始化

六,写在最后-总结

函数调用无非就是
①对象调用,(_thiscall)
②指针/引用指向了一个对象,通过指针/引用来解引用或者直接用引用来调用函数(_thiscall),跟①完全一致,可以归纳到①里面去
③直接调用函数(_cdecl),默认的C方式调用函数,如果在类里面static了函数,那么也是_cdecl编译
函数指针就这几种类型,区分开就好

七,更多函数指针的细节

可以去看看《深度探索C++对象模型》P174页,

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿维的博客日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值