在我的特定情况下,我有一个基类'Base',数据成员'A_var'。我希望任何派生类只有const访问该数据成员,在语法上与'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()',如下所示,也不起作用,因为'Derived'类调用私有非const'A()'。
protected:
const type_t& A() const {return A_var;}
private:
type_t& A() {return A_var;}
小差异可能看起来不是什么大不了的事,但在我的代码中有各种各样的宏开始访问该数据成员。因此,我必须为'Base'类和派生类提供不同的宏,这会扰乱代码的流动,包括读写。
更新 为了澄清,问题是使派生类和基类中的访问相同,语法。也就是说,例如,我可以调用函数f(),并在基类中调用时返回非const引用,但在派生类中调用时返回const引用。其动机是使派生类中的强制const访问无缝。我意识到可能没有办法做到这一点,但我要求以防万一。
更新 为了展示一个真实的例子(有2-3个这样的情况),这在代码中被大量使用:
test_files_var.current()->current_test()
我用
替换了它 #define TEST() test_files_var.current()->current_test()
因为派生类会通过不同的函数/成员访问test_files_var
,即testFiles()
,我必须有TEST()
的第二个定义,即DTEST()
。使用'宏'的次数更多地是问题,而不是它们中有多少次。
答案 0 :(得分:1)
如果我正确理解了您的问题,您希望允许访问派生类访问基类的私有变量,但是只读。
在这种情况下,您只需要定义一个受保护的常量引用变量并将其初始化为私有变量:
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
}
答案 1 :(得分:1)
哪里没有简单的内置解决方案。 但是一些模板魔法可能会成功:
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
函数中,您基本上具有相同的访问模式,如果需要,可以将其包装在宏中。
答案 2 :(得分:0)
您可以将基类更改为
class Base {
public:
Base() : A_cref(A_var) {}
private:
type_t A_var;
void f();
protected:
const type_t& A_cref;
};
额外的成员开销。
答案 3 :(得分:0)
如果宏可以从派生类中使用,它们只需要const访问 - 因此宏可以使用受保护的const访问函数。
要修改变量的宏必须使用私有变量,并且只能在基类中使用。
答案 4 :(得分:0)
如果您使用基类中的公共函数TEST()
替换test()
宏,问题就会消失:
class Base
{
public:
void test() { test_files_var.current()->current_test() }
private:
type_t test_files_var;
};