C ++ - 方法/成员访问

时间:2017-03-30 12:12:12

标签: c++ compilation private public

我们都知道私有方法和成员只能在类中访问,这与受保护的方法和成员在类和从该类派生的类中可访问的方式相同。但是这个“访问控制”在哪里? «访问控制»是否在编译时发生,或者编译器是否添加了在运行时控制它的附加机器代码?

我可以创建这样的类:

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()方法而没有错误?

3 个答案:

答案 0 :(得分:2)

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

因此,你的问题有点没有用。

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

«访问控制»在编译时发生,发生在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);

和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 寄存器中的第一个参数 this 以及堆栈中的下一个 __ 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