C++ - 方法/成员访问

C++ - Method/Member access

本文关键字:成员 访问 方法 C++      更新时间:2023-10-16

我们都知道私有方法和成员只能在类内部访问,就像受保护的方法和成员可以在类和从该类派生的类中访问一样。但是它的"访问控制"在哪里?"访问控制"是在编译时发生的,还是编译器在运行时添加额外的机器代码来控制它?

我可以创建一个这样的类吗:

class Print  
{
public: 
void printPublic();
private:
void printPrivate();
};
int main() 
{
Print print;  
print.printPublic() // Change this to printPrivate() after compiling the code
return(EXIT_SUCCESS);
}

然后在编译代码后编辑机器代码以调用printPrivate()而不是printPublic()方法而没有错误?

一旦你摆弄了机器代码,你就不再是编译C++,而是直接用机器代码编程。

因此,你的问题有些没有实际意义。

您可以将访问说明符视为本质上是编译时指令,但请注意,编译器可以根据它们做出优化选择。换句话说,它可能是其中之一。C++标准也不必对此进行任何说明。

"访问控制"发生在编译时,并且仅适用于C ++代码。 你甚至不需要编辑机器代码 - 你可以轻松地从汇编语言调用私有方法 - 所以这表明这仅适用于C ++限制。 当然,没有任何额外的机器代码在运行时控制它 - 这根本不可能控制谁调用方法。

只需演示. 注意函数名称,它如何损坏取决于 x86 或 x64 编译以及编译器可能 - 我的CL编译器和 x64 平台蝙蝠演示可以轻松更改为 x86 或其他编译器

C++ 代码

class Print  
{
public: 
void printPublic();
private:
void printPrivate();
};
// must be not inline or referenced from c++ code or will be droped by compiler!
void Print::printPrivate()// thiscall
{
DbgPrint("%s<%p>n", __FUNCTION__, this);
}
void Print::printPublic()// thiscall
{
DbgPrint("%s<%p>n", __FUNCTION__, this);
}
extern "C"
{
// stub impemeted in asm
void __fastcall Print_printPrivate(Print* This);
void __fastcall Print_printPublic(Print* This);
};

Print p;
//p.printPrivate();//error C2248
p.printPublic();
Print_printPrivate(&p);
Print_printPublic(&p);

和 ASM 代码(适用于ML64)

_TEXT segment 'CODE'
extern ?printPrivate@Print@@AEAAXXZ:proc
extern ?printPublic@Print@@QEAAXXZ:proc
Print_printPrivate proc
jmp ?printPrivate@Print@@AEAAXXZ 
Print_printPrivate endp
Print_printPublic proc
jmp ?printPublic@Print@@QEAAXXZ 
Print_printPublic endp
_TEXT ENDS
END

另请注意,对于 x86,所有 C++ 方法都使用thisCall调用约定 - 第一个参数在 ECX 寄存器中,下一个参数在堆栈中,至于__stdcall- 所以如果方法没有参数(实际上是一个这个),我们可以按原样使用__fastcallfor asm 函数,如果存在参数,我们需要将EDX推送到汇编器存根中的堆栈。 对于 x64 没有这个问题 - 这里只有一个调用约定,但这一切都已经与主要问题无关。


带有额外参数的 x86 代码示例,用于演示如何将__fastcall转换为__thiscall

class Print  
{
public: 
void printPublic(int a, int b)// thiscall
{
DbgPrint("%s<%p>(%x, %x)n", __FUNCTION__, this, a, b);
}
private:
void printPrivate(int a, int b);
};
// must be not inline or referenced from c++ code or will be droped by compiler!
void Print::printPrivate(int a, int b)// thiscall
{
DbgPrint("%s<%p>(%x, %x)n", __FUNCTION__, this, a, b);
}
extern "C"
{
// stub impemeted in asm
void __fastcall Print_printPrivate(Print* This, int a, int b);
void __fastcall Print_printPublic(Print* This, int a, int b);
};
Print p;
//p.printPrivate(1,2);//error C2248
p.printPublic(1, 2);
Print_printPrivate(&p, 1, 2);
Print_printPublic(&p, 1, 2);

和 ASM

.686p
_TEXT segment
extern ?printPublic@Print@@QAEXHH@Z:proc
extern ?printPrivate@Print@@AAEXHH@Z:proc
@Print_printPrivate@12 proc
xchg [esp],edx
push edx
jmp ?printPrivate@Print@@AAEXHH@Z 
@Print_printPrivate@12 endp
@Print_printPublic@12 proc
xchg [esp],edx
push edx
jmp ?printPublic@Print@@QAEXHH@Z
@Print_printPublic@12 endp
_TEXT ends
end

«访问控制»发生在编译时