设计类有太多set,get,该怎么办啊

fengfeng2003 2003-08-26 07:55:29
现设计了一个类,但类中大部分成员变量需要set,get函数
总觉着不太好,这不是破坏了封装了吗?但这些变量确实需要set,get
如果直接让这些变量公有,岂不更差吗?
到底该怎么办啊?
...全文
360 50 打赏 收藏 转发到动态 举报
写回复
用AI写文章
50 条回复
切换为时间正序
请发表友善的回复…
发表回复
shenyiwen 2003-08-30
  • 打赏
  • 举报
回复
我个人的经验, 不要玩那些花招, 老老实实地对每个属性写get/set. 如果怕
影响效率就变成inline.
get/set是函数, 函数相当于一个接口, 可以将内部实现和外部隔离. 一个类
开始可能只是简单的对内部成员直接get/set, 但是到后来这个类变得越来越
复杂或者派生的时候, 可能该get/set也会添加许多新的条件, 甚至原来的成员变量都
已不存在, 而已由其他运算替代, 这时虽然内部get/set已经面目全非, 但在
外面看来还是一样的, 从而达到实现和接口的隔离. 如果直接把数据成员变成
则这些灵活性都丧失了. 举个例子:

最初一个点的类如:
class Point {
public:
virtual float getX() const { return _x; }
virtual void setX( float x ) { _x = x; }
private:
float _x;
};

后来发现所有点必须坐标都大于0, 则可改成
float getX() const { if( _x < 0 ) return 0; return _x; }

后来又要引入一个虚拟的平均点:
class AveragePoint : public Point {
public:
virtual float getX() const { return (_p1->getX()+_p2->getX())/2; }
virtual void setX( float x ) { }
private:
Point *_p1, *_p2;
};

虽然内部实现变了三次, 但是接口的get/set都不变, 外面使用Point的地方如果没有特殊
要求则无须改动. 相反如果直接引用内部成员则外部必须也相应改动三次.
rtdb 2003-08-29
  • 打赏
  • 举报
回复
嘿嘿, 两位都是高手啊, 够楼主研究一阵子了。
sandrowjw 2003-08-29
  • 打赏
  • 举报
回复
呵呵,模板的灵活性果然无可比拟。
sandrowjw 2003-08-29
  • 打赏
  • 举报
回复
嗯,看来还是模板灵活性好。
oopig 2003-08-29
  • 打赏
  • 举报
回复
不过得承认sandrowjw(伊卡洛斯)的方法一般情况下确实很实用,虽然不够时髦:p
oopig 2003-08-29
  • 打赏
  • 举报
回复
宏在一般情况下可以解决问题,但是也有自身的限制。比如对于某个属性的get/set方法进行定制就不方便;而模版方法就可以通过特化很方便地实现。
#include <iostream>
using namespace std;


struct Record
{
int attr1;
unsigned attr2;
};

class Sample
{
private:
Record _record;
void OnAttr2Changed(unsigned bef, unsigned aft)
{
cout << "attr2 changed from " << bef << " to " << aft << endl;
}
public:
Sample()
{
_record.attr1 = 0;
_record.attr2 = 0;
}
template <typename T, T Record::*pt>
void set(const T &data)
{
_record.*pt = data;
}
template <typename T, T Record::*pt>
T get()
{
return _record.*pt;
}
};

template <>
void Sample::set<unsigned, &Record::attr2>(const unsigned &data)
{
unsigned bef = _record.*(&Record::attr2);
unsigned aft = data;
_record.*(&Record::attr2) = data;
//激发属性变化事件
OnAttr2Changed(bef, aft);
}

int main()
{
Sample sam;
//处理第一个属性
int item1 = sam.get<int, &Record::attr1>();
sam.set<int, &Record::attr1>(item1 + 100);
//处理第二个属性
unsigned item2 = sam.get<unsigned, &Record::attr2>();
//这里会激发属性变更事件
sam.set<unsigned, &Record::attr2>(item2 + 100);
return 0;
}

sandrowjw 2003-08-29
  • 打赏
  • 举报
回复
实际上用宏就可以解决了(当然前提是属性都是assignable的)

#define PROPERTY_RW(type, name) \
private:\
type name;\
public:\
void set_##name(type n)\
{ name = n; }\
type get_##name()\
{ return name; }

#define PROPERTY_RO(type, name)\
....

class A
{
PROPERTY_RW(int, i)
PROPERTY_RW(char, c)
};
magicblue 2003-08-29
  • 打赏
  • 举报
回复
so, providing semantic thing is the first step that we should consider. providing syntax is a paradox at here. we can do a compromise about syntax if we can't do the first step. just like dealing with data with batch in a form of struct.
oopig 2003-08-29
  • 打赏
  • 举报
回复
magicblue(小飞侠):
确实是跑题了
magicblue 2003-08-29
  • 打赏
  • 举报
回复
1 and 2 for what? could you say it in detail?
i mean what you have done is what the purpose want to avoid
oopig 2003-08-29
  • 打赏
  • 举报
回复
magicblue(小飞侠):
至少有两种方法:
1.如果需要,可以再加两种结构ReadOnly和WriteOnly,分别只实现get和set方法
2.或者可以把特化的set/get方法设置成protected或者private
magicblue 2003-08-29
  • 打赏
  • 举报
回复
oopig:

but i want to ask what is the difference with the original?
in my opinion, the calling of set and get method have been doubled, the class that originally has the datas have to use those get and set too.
skywater 2003-08-28
  • 打赏
  • 举报
回复
to magicblue(小飞侠), oopig(面向对象的猪)
举个例子:
class A
{
private:
int i;
public:
int get_i();
int set_i(int j);
};
上面的这个类,专门为i设计读写的接口,这样实在是没有必要。须知接口的目的之一是为了数据验证和防止错误。但是如果以这样的代价来达到验证防错的效果,在整个设计上是得不偿失。

“所以如果类里面要为某个数据成员设计get, set等方法,应该毫不犹豫地改成public”,这句话的内容,如果不是Bjarne Stroustrup说过的,那也是某个大师级人物说过的,改天找出原文来。
liu_feng_fly 2003-08-28
  • 打赏
  • 举报
回复
<<c++沉思录>>的作者是这样认为的,如果一个成员变量要被频繁的get/set,那不如就直接设置成public
magicblue 2003-08-28
  • 打赏
  • 举报
回复
> 所以如果类里面要为某个数据成员设计get, set等方法,应该毫不犹豫地改成public

这观点实在是...晕...
B.S说过这话??
oopig 2003-08-28
  • 打赏
  • 举报
回复
数据还是在类中,没有剥离出来。你也可以把struct作为一个内嵌的类型。
fengfeng2003 2003-08-28
  • 打赏
  • 举报
回复
oopig(面向对象的猪)
看到你巧妙的解决方法,心里狂喜,但回头反思又发现了问题:
与rtdb(东临碣石)的方法相比,接口几乎完全一样
但rtdb(东临碣石)的方法把数据保留在类中。而你的方法强行把数据从类中
剥离出来,又使用了一个结构体。
事实上数据应该保留在类中。
单从这一方面看,好像rtdb(东临碣石)的方法更优雅。
不知你是怎样评价这两种方法的
fengfeng2003 2003-08-28
  • 打赏
  • 举报
回复
你的解决方法更妙
我真是受益匪浅,以后一定多多讨教。
oopig 2003-08-28
  • 打赏
  • 举报
回复
我觉得你提的这个问题很好,让我很感兴趣。
fengfeng2003 2003-08-28
  • 打赏
  • 举报
回复
明白了,多谢各位
尤其是 oopig(面向对象的猪)
加载更多回复(30)

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧