问题描述
考虑以下代码库设计模式:
template<typename T>
class Foo {
public:
Foo(T t) : class_member_{t} {}
const T class_member() const { return class_member_;}
Foo(const Foo& other ) {
class_member_ = other.class_member_;
}
Foo& operator=(const Foo& other) {
class_member = other.class_member_;
return *this;
}
template<template<class> class U,typename V>
friend auto extend(U<V>& u,V v);
void update_from_hidden() {
class_member_ = hidden_member_;
}
protected:
T hidden_member_{class_member_ + 1};
private:
T class_member_;
void update_class_member(T new_val) { class_member_ = new_val;}
};
template<template<class> class T,typename U>
auto extend(T<U>* tt,U val) {
auto impl = [] (T<U>* t,U val) {
t->hidden_member_ += 5; // okay I want this lambda to be able to
// modify Foo::hidden_member
t->class_member_ = 7; // Invalid,I don't want this lambda to have
// access to Foo's private members
return *t;
};
}
int main() {
Foo<int> foo(3);
foo = extend(&foo,2);
return foo.class_member();
}
现在,lambda 主体中的这两行和 main 中的这一行:
t->hidden_member_ += 5;
t->hidden_member_ = 7;
// main
foo = extend(&foo,2);
不会编译,因为这些成员在此上下文中受保护和私有,并且 operator=()
无法解析值 2
。
在尝试保留此代码结构的同时,我希望通过某个任意类对象的友元函数的这些类型的 lambda 能够直接访问类的受保护成员,同时仍然限制它们访问类的私有成员和两个变量和私人功能。
这是否可以实现,如果可以,我至少需要对此类和/或 lambda 执行哪些操作才能实现此行为?
如果没有,是否还有其他适合该模型的现有代码模式?
我想将特定方法抽象到类之外,但我更喜欢在此上下文中使用 lambda。事实上,我更希望有这样的东西,但这不是我所知道的有效 C++ 代码......
class Bar {
public:
Bar(int val) : member_{val} {
protected:
int hidden_;
private:
int member_;
};
auto extend = [](Bar* bb,int val) {
friend class Bar; // not valid or legal as far as I know
bb->hidden_ += 3; // I want this to be valid
bb->member_ = 5; // I want this to be blocked,not valid
return *bb;
};
这是我遇到障碍的地方...我关心的不是方法的实现,而是类 Foo
和 lambda extend
如何通过朋友或我上面描述的方式和上下文中的其他一些机制......不知道在这里做什么。
-编辑-
好的,这是一个用例场景。
假设我有一个 WaterPipe
类,它具有只能在类本身内更改的私有成员。它有一些更新方法可以在内部更改该私有成员。现在,它具有受保护的成员,这些成员不能被类的外部访问,但希望将它们暴露给 lambda 来修改这个类的维度或状态,而不是它的内部属性或行为。
class WaterPipe {
public:
WaterPipe(float length,float diameter)
: length_{length},diameter_{diameter},has_changed{false}
{
calculate_props();
}
friend extend(WaterPipe* pipe,float newLength,float newDiameter);
const auto length() const { return length_; }
const auto diameter() const { return diameter_; }
const auto volume() const { return volume_flow_; }
const auto direction() const { return direction_flow_; }
const auto pressure() const { return pressure_flow_; }
protected:
float length_;
float diameter_;
void recalculate() { calculate_pops(); }
private:
float volume_flow_;
float direction_flow_;
float pressure_flow_;
void calculate_props() {
// implementation here
}
};
auto extend_water_pipe(WaterPipe* pPipe,float newDiameter) {
bool changed = false;
auto impl = [](WaterPipe* pipe,float newDiameter)
if (pipe->length_ != newLength || pipe->length_ != newDiameter) {
pipe->length_ = newLength;
pipe->diameter_ = newDiameter;
pipe->recalculate();
changed = true;
}
return pipe;
};
if ( !changed ) { return pPipe; }
return impl(pPipe,newLength,newDiamter)();
}
在一些 GUI 应用程序中:
void object_construction_in_app(...) {
// user grabs water pipe drawing tool
// user clicks point on graph node and holds mouse down
// drags it in some direction,stops and releases the mouse
// this calls the constructor on the pipe giving it the length
// the diameter was already set via the `water pipe drawing tool`
// create a new pipe object here with specified values
// and store it into some container to be rendered.
}
// some frames later
void object_update(...) {
// user selects already constructed pipe
// and decides to either change it's diameter through context menu
// or changes its length by clicking on one of its ends and starts
// to drag it again...
// get object from container and use `friend function - lambda`
// to update it's dimensions,return back that object to have
// it be rendered,store it into some other container,such as
// a queue,etc...
}
水管将计算它自己的内部值...外部朋友 lambda 将仅通过重置长度或直径并调用受保护的 recalculate()
函数来访问它的受保护成员,然后调用该类的内部私有calculate_props()
函数。然后 lambda 要么返回一个指向类对象的指针,要么返回一个指向该类的顺从指针以允许进行复制或赋值。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)