仅授予派生类对基类数据成员/函数的 const 访问权限

Giving derived class only const access to base class data members/functions

本文关键字:函数 const 访问 权限 访问权 数据成员 派生 基类      更新时间:2023-10-16

在我的特定情况下,我有一个基类"Base",带有一个数据成员"A_var"。我希望任何派生类都只能以与"Base"类在语法上相同的方式访问该数据成员。

如果它是受保护的或私有的,则派生类分别具有完全访问权限或没有访问权限。我可以将其设为私有,并创建一个返回 const 引用的受保护函数,但随后访问将在语法上有所不同。

class Base {
protected:
    const type_t& A() const {return A_var;}
private:
    type_t A_var;
    void f();
};
class Derived : public Base{
public:
    void g();
};
//access in Base class
void Base::f() {
    type_t value = A_var;
    A_var = value;
}
//access in Derived class
void Derived::g() {
    type_t value = A();
    A() = value; //Error, const reference; good
}
重载"A()",

如下所示,也不起作用,因为"派生"类调用私有非常量"A()"。

protected:
    const type_t& A() const {return A_var;}
private:
    type_t& A() {return A_var;}

微小的差异可能看起来没什么大不了的,但在我的代码中,有各种宏从访问该数据成员开始。因此,我必须为"Base"类和派生类使用不同的宏,这会破坏代码的读取和写入流。

更新:澄清一下,问题是在语法上使派生类和基类中的访问相同。也就是说,例如,我可以调用一个函数 f(),并让它在基类中调用时返回一个非常量引用,但在派生类中调用时返回一个常量引用。动机是使派生类中的强制 const 访问无缝。我意识到可能没有办法做到这一点,但我问以防万一。

更新:为了提供一个真实的例子(有 2-3 个这样的情况),这在代码中被大量使用:

 test_files_var.current()->current_test()

我用

 #define TEST() test_files_var.current()->current_test()

因为派生类将通过不同的函数/成员访问test_files_var,即 testFiles(),我必须对TEST()有第二个定义,即 DTEST() .问题更多地取决于"宏"的使用次数,而不是它们的数量。

哪里没有简单的内置解决方案。但是一点模板魔术可能会起到一个作用:

template <class NonConst>
struct Matcher {
    template <class AnyOther>
    static const AnyOther &get(AnyOther &obj) { return obj; }
    static NonConst &get(NonConst &obj) { return obj; }
};
class Base {
public:
    Base() : a_(42) { }
public:
    virtual void Fun() {
        Matcher<Base>::get(*this).A();
    }
    const int &A() const {
        std::cout << "const" << std::endl;
        return a_;
    }
    int &A() {
        std::cout << "no const" << std::endl;
        return a_;
    }
private:
    int a_;
};
class Derived : public Base {
public:
    void Fun() {
        Matcher<Base>::get(*this).A();
    }
};
int main(int argc, const char * argv[]) {
    Derived d;
    d.Fun();
    Base b;
    b.Fun();
    return 0;
}

上面的代码将输出:const no const .

因此,在这两个Fun函数中,您基本上具有相同的访问模式,如果需要,您可以将其包装在宏中。

如果我正确理解您的问题,您希望授予对派生类的访问权限访问基类的私有变量的权限,但只能使用。

在这种情况下,您只需定义一个受保护的常量引用变量并将其初始化为私有变量:

class Base {
public: 
    Base() : cA(A_var) { ... }  // to be completed with rule of 3
protected:
    const type_t& cA;
private:
    type_t A_var;
    void f();
};

派生类中的访问随后使用常量引用:

//access in Derived class
void Derived::g() {
    type_t value = cA;
    //cA = value; //Error, const reference: can't assign 
}

现场演示

您可以将基类更改为

class Base {
public:
    Base() : A_cref(A_var) {}
private:
    type_t A_var;
    void f();
protected:
    const type_t& A_cref;
};

具有额外的成员开销。

如果宏可从派生类中使用,则它们只需要 const 访问 - 因此宏可以使用受保护的 const 访问函数。

要修改变量的宏必须使用私有变量,并且只能在基类中使用。

如果您将

TEST()宏替换为基类中的公共函数test(),您的问题似乎会消失:

class Base
{
public:
    void test() { test_files_var.current()->current_test() }
private:
    type_t test_files_var;
};