编程风格:对象与引用或值通道?(c++)
Programming style: object with passages by references or value? (c++)
这是一个关于编程风格的一般性问题。假设我有一个对象Line
,它有一些方法和私有变量Point point_a_
和Point point_b_
。假设在某一点上我需要改变这两点的位置。在以下情况中,您更喜欢哪种编程风格?它们都做同样的事情(或者应该做的事情:我没有编译,但看起来很简单)。
案例1
Class Line {
public:
Line(Point point_a, Point point_b) : point_a_(point_a), point_b_(point_b) {}
void UpdatePoints(Point point_a, Point point_b) {
point_a_ = point_a; point_b_ = point_b;
}
double Distance();
private:
Point point_a_;
Point point_b_;
};
int main (int argc, char * const argv[]) {
Point point_a(0,0,0);
Point point_b(1,1,1);
Line line(point_a,point_b);
std::cout<<line.Distance()<<"n";
point_a.x = 1;
line.UpdatePoints(point_a,point_b);
std::cout<<line.Distance()<<"n";
}
案例2
Class Line {
public:
Line(Point point_a, Point point_b) : point_a_(point_a), point_b_(point_b) {}
Point& point_a() { return point_a_; }
Point& point_b() { return point_b_; }
double Distance();
private:
Point point_a_;
Point point_b_;
};
int main (int argc, char * const argv[]) {
Point point_a(0,0,0);
Point point_b(1,1,1);
Line line(point_a,point_b);
std::cout<<line.Distance()<<"n";
line.point_a().x = 1;
std::cout<<line.Distance()<<"n";
}
情况3
Class Line {
public:
Line(Point* point_a, Point* point_b) : point_a_(point_a), point_b_(point_b) {}
double Distance();
private:
Point* point_a_;
Point* point_b_;
};
int main (int argc, char * const argv[]) {
Point point_a(0,0,0);
Point point_b(1,1,1);
Line line(&point_a,&point_b);
std::cout<<line.Distance()<<"n";
point_a.x = 1;
std::cout<<line.Distance()<<"n";
}
任何反馈都非常感谢!!
谢谢!
[EDIT]在我的软件中速度是最重要的!
在这个简单的场景中,我可能只使用公共成员变量。
否则我会提供返回const引用的getter和匹配的setter。
class Line {
public:
Line(const Point& p1, const Point&p2) : m_p1(p1), m_p2(p2) {}
const Point& p1() const
{ return m_p1; }
const Point& p2() const
{ return m_p2; }
void setP1(const Point& p1)
{ m_p1 = p1; }
void setP2(const Point& p2)
{ m_p2 = p2; }
private:
Point m_p1;
Point m_p2;
};
第三种情况完全不适用,因为它完全违反了封装原则。情形二也一样,只是程度稍小一些。我更喜欢选项一,但你有没有考虑过让点不可变,并在它改变时强迫你创建一个新对象?
如果我多年前没记错的话,这也是一种迂腐,从技术上讲,一条线在两个方向上无限延伸。您实际上表示的是一行段。
情况2不比公共成员变量好。特别是,它不封装任何东西。
情形3使得点的所有权不明确。考虑一下,如果你的点是调用函数中的局部变量,然后它们超出了作用域,会发生什么。与公共成员变量相比,它也没有提供任何好处。
所以在这三个选项中,我认为情况1是最干净的。其他选项包括:
- 直接使用公共成员变量。
- 使
Line
不可变 - 使用
set
和get
函数
我会选择case 1或不可变的Line类。
Case 2允许在不知道其包含行的情况下更改Point对象。在某些时候,您可能需要这条线知道它的点是否已经改变。
情况3要么使Line对象依赖于点的生存期,要么使Line成为点的所有者,这在API中是不清楚的。
不可变的Line允许你用新的点创建一个新的Line对象
Case 4—首选const引用而不是值(或指针):
class Line
{
public:
Line(const Point& a, const Point& b) : a_(a), b_(b)
{}
const Point& get_a() const { return a_; }
const Point& get_b() const { return b_; }
void set_a(const Point& a) { a_ = a; }
void set_b(const Point& b) { b_ = b; }
private:
Point a_;
Point b_
};
这是更好的,因为它强制封装——在构造之后改变类中保存的变量的唯一方法是一个特定的mutator方法。
访问器返回一个const引用,因此它们不能被修改(可以从它们复制)。
整个类都是const-correct。
在这种情况下,引用比指针更好,因为它们被保证不为NULL(除非你特别打破了这个保证)。
考虑另一个选项:
class Segment {
public:
Segment(Point point_a, Point point_b);
Point point_a() const;
Point point_b() const;
private:
Point point_a_;
Point point_b_;
};
double Distance( Segment seg );
int main (int argc, char * const argv[]) {
Point point_a(0, 0, 0);
Point point_b(1, 1 ,1);
Segment seg(point_a, point_b);
std::cout << Distance(seg) << "n";
point_a.x = 1;
seg = Segment(point_a, point_b); // reset
std::cout << Distance(seg) << "n";
}
我按照上面的建议使用了名称Segment。这种风格更接近函数式编程风格。段是不可变的,除非你用通用赋值语法显式地重置它。Distance不是成员函数,因为它可以通过Segment的公共接口实现。
问候,div, rzej
- 在AVX通道中混洗的最佳方式
- 在Arduino中将PWM通道命名为LEDC是否有特定原因
- 空 grpc 客户端通道
- 如何在进程之间创建双向通道?
- 在 libsndfile 中一次写入一个通道
- 如何在 C++ 中建立进程之间的双向通道?
- 防止控制台在通道字符(在 c++ 中)中输入空格(即空格、制表符和换行符)
- 在RAW图像中提取RGB通道值的库或方法
- 深度缓冲区未填充阴影贴图渲染通道中的数据
- 如何将具有两个通道的垫子转换为矢量<int><矢量>?
- QWeb通道新客户端获得初始状态?
- Gdiplus位图没有Alpha通道
- Go/C++gRPC客户端通道和存根生命周期
- HBITMAP 能否包含 alpha 通道信息?
- 编写具有 2 个通道的自定义 QIODevice
- 保存的 Gdiplus::位图始终具有 Alpha 通道 (RGBA/ARGB)
- 有没有办法使用 glDrawPixel 渲染单通道灰度图像?
- gRPC C++尝试在无法访问的 IP 上连接通道时阻止客户端
- boost::log 设置"Channel"通道记录器中的属性
- 如何在课堂上正确使用升压通道(和光纤)?