记录:C++ 在类外访问类的私有成员(非侵入式)

440 阅读1分钟

一般地,C++ 不希望我们在类外直接访问类的私有成员,就连 decltype() 也不行:

class A
{
    int foo(int);
};
inline static constexpr const decltype(&A::foo) c_pfn_A_foo = &A::foo; // ERR

笔者在如下两个 StackOverflow 问题中(逐步)得到了满意的解答:

成品如下所示:

// PrivateAccess.h
#pragma once

template <typename Tag, typename Tag::pfn_t pfn>
struct tag_bind_pfn
{
    // 这句是核心之一,巧妙利用 friend 在模板外定义了函数,还是 constexpr!
    friend constexpr typename Tag::pfn_t pfn_of(Tag) { return pfn; }
};
// main.cpp
#include <cstdio>
#include "PrivateAccess.h"

class A
{
    int foo(int a) { return a; }
};

struct tag_A_foo
{
    using pfn_t = int (A::*)(int);
    // 这句也很关键,不信你去掉试试,会编译报错
    friend constexpr typename pfn_t pfn_of(tag_A_foo);
};
// 这句是核心之一,编译器允许在模板显式实例化时访问私有成员,使这一切成为可能
template struct tag_bind_pfn<tag_A_foo, &A::foo>;
// 这句纯粹向大家展示一下它可以 constexpr
inline static constexpr const auto c_pfn_A_foo = pfn_of(tag_A_foo{});

int main()
{
    A p;
    auto ret = (p.*(c_pfn_A_foo))(1);
    printf("%d\n", ret);
    return 0;
}