首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >命名构造函数习惯用法和新运算符

命名构造函数习惯用法和新运算符
EN

Stack Overflow用户
提问于 2011-08-10 20:32:36
回答 3查看 6.3K关注 0票数 18

我使用命名构造函数的习惯用法来创建对象,因为我有很多具有相同参数的调用,但对象的创建方式应该不同。

C++ FAQ告诉我们如何做到这一点。它还告诉我们如何强制对象被堆分配。然而,它确实没有告诉我们如何将命名构造函数习惯用法与new运算符一起使用。

因为new需要调用构造函数,所以我们不能直接调用命名构造函数。因此,我找到了两种解决此问题的方法:

我创建了一个额外的复制构造函数,并希望优化编译器不会创建临时对象。

代码语言:javascript
复制
class point_t {
    int X,Y;
    point_t(int x, int y) : X(x), Y(y) { }
  public:
    point_t(const point_t &x) : X(x.X), Y(x.Y) { }
    static point_t carthesian(int x, int y) { return point_t(x,y); }
    static point_t polar(float radius, float angle) {
      return point_t(radius*std::cos(angle), radius*std::sin(angle));
    }

    void add(int x, int y) { X += x; Y += y; }
};



int main(int argc, char **argv) {
  /* XXX: hope that compiler doesn't create a temporary */
  point_t *x = new point_t(point_t::carthesian(1,2));
  x->add(1,2);
}

另一个版本是创建单独的命名构造函数。因为函数重载在返回类型上不起作用,所以我使用了两个不同的名称,这很难看。

代码语言:javascript
复制
class point_t {
    int X,Y;
    point_t(int x, int y) : X(x), Y(y) { }
  public:
    /* XXX: function overloading doesn't work on return types */
    static point_t carthesian(int x, int y) { return point_t(x,y); }
    static point_t *carthesian_heap(int x, int y) { return new point_t(x,y); }
    void add(int x, int y) { X += x; Y += y; }
};

int main(int argc, char **argv) {
  point_t *x = point_t::carthesian_heap(1,2);
  x->add(1,2);
}

有没有更漂亮的版本可以与示例代码相媲美?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-08-10 21:18:46

为此,您可以完全避免使用命名构造函数习惯用法,而是使用附加的虚拟枚举参数来选择构造函数。

代码语言:javascript
复制
enum Carthesian {carthesian};
enum Polar {polar};
class point_t {
    int X,Y;
  public:
    point_t(int x, int y) : X(x), Y(y) { } // may keep as a default
    point_t(Carthesian, int x, int y) :X(x),Y(y){}
    point_t(Polar, float radius, float angle)
    : X (radius*std::cos(angle)), Y(radius*std::sin(angle)) {}
    void add(int x, int y) { X += x; Y += y; }
};

int main(int argc, char **argv) {
  point_t *x = new point_t(carthesian,1,2);
  point_t *y = new point_t(polar,0,3);
  x->add(1,2);
}

它简单、可移植,您将看到的唯一开销是传递虚拟枚举值。在极少数情况下,这种开销对你来说太高了,它可以通过包装函数调用来消除,即使构造本身不是内联的,如下所示:

代码语言:javascript
复制
enum Carthesian {carthesian};
enum Polar {polar};
class point_t {
    int X,Y;
    void initCarthesian(int x, int y); // may be long, not inlined
    void initPolar(float radius, float angle);
  public:
    point_t(int x, int y) : X(x), Y(y) { } // may keep as a default
    point_t(Carthesian, int x, int y)
    {initCarthesian(x,y);} // this is short and inlined
    point_t(Polar, float radius, float angle) {initPolar(radius, angle);}
    void add(int x, int y) { X += x; Y += y; }
};

另一种方法是使用派生类进行构造。当使用内部类时,我认为它导致了一个相当好的语法:

代码语言:javascript
复制
class point_t {
    int X,Y;
  public:
    struct carthesian;
    struct polar;
    point_t(int x, int y) : X(x), Y(y) { } // may keep as a default
    void add(int x, int y) { X += x; Y += y; }
};

struct point_t::carthesian: public point_t
{
  carthesian(int x, int y):point_t(x,y){}
};

struct point_t::polar: public point_t
{
  polar(float radius, float angle):point_t(radius*std::cos(angle),radius*std::sin(angle)){}
};

int main(int argc, char **argv) {
  point_t *x = new point_t::carthesian(1,2);
  point_t *y = new point_t::polar(0,3);
  x->add(1,2);
  return 0;
}
票数 14
EN

Stack Overflow用户

发布于 2011-08-10 20:53:33

这真的是一个问题吗?在我的经验中,类往往要么在大部分时间内动态分配,要么很少分配。表示值的类,比如这里的point_t类,属于第二类,而表示实体(即具有标识的东西)的类属于第一类。

因此,我的建议是为每个类选择您认为最好的方法,并只提供这种方法。请注意,您可以始终返回一个小的直接分配的对象,该对象有一个指向较大对象的私有指针,如在the Handle-Body idiom中。

另一方面,其他答案显示了如何在接受相同数量和类型的参数的构造函数之间消除歧义。按照这种思路,另一种方法是为参数引入特定类型,如下所示:

代码语言:javascript
复制
class radius_t {
    float R;
  public:
    explicit radius_t(float r) : R(r) {}
    operator float() const { return R; }
};

class angle_t {
    float A;
  public:
    explicit angle_t(float a) : A(a) {}
    operator float() const { return A; }
};

class point_t {
    float X,Y;
  public:
    point_t(float x, float y) : X(x), Y(y) { }
    point_t(radius_t radius, angle_t angle) :
      X(radius*std::cos(angle)), Y((radius*std::sin(angle)) {
    }

    void add(int x, int y) { X += x; Y += y; }
};

int main(int argc, char **argv) {
  point_t *x = new point_t(radius_t(1),angle_t(2));
  x->add(1,2);
}
票数 4
EN

Stack Overflow用户

发布于 2015-03-27 16:17:23

我还没有看到的一种方法是重载构造函数,使堆分配使用最后一个参数作为输出参数(假设第二个函数从技术上讲不是构造函数,它不返回实例)。结果将类似于(作为您的第二个代码片段的基础):

代码语言:javascript
复制
class point_t {
    int X,Y;
    point_t(int x, int y) : X(x), Y(y) { }
  public:
    /* XXX: function overloading doesn't work on return types */
    static point_t carthesian(const int x, const int y) { return point_t(x,y); }
    static void carthesian(const int x, const int y, point_t * & point) { point = new point_t(x,y); }
    void add(int x, int y) { X += x; Y += y; }
    void add(const point_t & point) { this->X += point.x; this->Y += point.y; }
};

int main(int argc, char **argv) {
    point_t p1 = point_t::carthesion(1, 2);
    point_t * p2;
    point_t::carthesian(1, 2, p2);

    p2->add(p1);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7010827

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档