C++ - Method/Member 访问
C++ - Method/Member access
我们都知道私有方法和成员只能在 class 内部访问,就像保护方法和成员在 class 和 class 派生的class。但是,它的“访问控制”在哪里? “访问控制”是在编译时发生,还是编译器添加了在运行时控制它的额外机器代码?
我可以像这样创建一个 class 吗:
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 平台的演示 bat 它可以很容易地更改为 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);
和汇编代码(对于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 调用约定 - this 在 ECX[ 中的第一个参数 this =42=] 寄存器和堆栈中的下一个 __stdcall - 所以如果方法没有参数(真的是一个 this )我们可以按原样使用 __fastcall 作为 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
我们都知道私有方法和成员只能在 class 内部访问,就像保护方法和成员在 class 和 class 派生的class。但是,它的“访问控制”在哪里? “访问控制”是在编译时发生,还是编译器添加了在运行时控制它的额外机器代码?
我可以像这样创建一个 class 吗:
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 平台的演示 bat 它可以很容易地更改为 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);
和汇编代码(对于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 调用约定 - this 在 ECX[ 中的第一个参数 this =42=] 寄存器和堆栈中的下一个 __stdcall - 所以如果方法没有参数(真的是一个 this )我们可以按原样使用 __fastcall 作为 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