【问题标题】:How is the constructor used in C++? Why does it seem to allow using it as a parameter?C++中如何使用构造函数?为什么它似乎允许将其用作参数?
【发布时间】:2015-11-03 07:21:45
【问题描述】:

我偶然发现了这个question(这是一个不同的例子)。大多数人说构造函数不返回任何东西。 但是,为什么我的示例有效?

sequence(1, 2) 是一个构造函数,显然可以在我的机器上使用。我使用 g++ 并尝试不带选项和 C++11 选项。两者都适用于我的情况。

这个例子来自一门课​​程。我照原样复制,不管public 是否有意义,或者别的什么。

例子:

#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;

void printer(int i) {
    cout << i << ", ";
}

struct sequence {
    int val, inc;
public:

    sequence(int s, int i) : val(s), inc(i) {
        cout << "Sequence(" << val << ", " << inc << ")" << endl;
    }

    operator int() const {//LINE I
        int r = val;
        cout << r << endl;
        return r;
    }
};

int main() {
    vector<int> v1(7);
    fill(v1.begin(), v1.end(), sequence(1, 2)); //LINE II
    for_each(v1.begin(), v1.end(), printer);
    return 0;
}

结果:

Sequence(1, 2)
1
1
1
1
1
1
1
1, 1, 1, 1, 1, 1, 1, 

更新

谢谢大家的回答。但我仍然很困惑,无法进入我的脑海,我认为可能缺少正确的术语。

到目前为止,我想我明白了:

  • sequence 是一个 struct 对象
  • sequence(int, int) 是构造函数定义,不返回任何内容
  • sequence 上的 () 运算符仅返回 val 值。

那么为什么它会起作用:

  • sequence(1,2) 的调用会创建一个可以访问和读取的临时对象
  • () 用于填充相应的元素。基本上fill 使用sequence() 来获取要填写的值。
  • fill 完成后,临时对象被销毁。它的作用域是函数fill的作用域

到目前为止,这听起来对吗?

【问题讨论】:

  • 请定义work。这里的working 是什么?你期待什么?
  • 因为你有一个operator int() 用于将sequence 对象转换为int
  • 注意,public 在你的struct 中真的没用
  • @Elyasin “我的问题是不是有点愚蠢?” 是的,因为根据定义,构造函数 return 没有任何意义。
  • @Elyasin here 是一些关于显式类型转换的文档。 Here 是一些关于用户定义的转换。 sequence(1,2) 是一种显式类型转换,它会生成 sequence 类型的临时对象,然后可以使用用户定义的转换运算符隐式转换为 int

标签: c++ constructor return


【解决方案1】:

因为您有operator int(),它将您的sequence 类对象转换为1。您可以轻松地观察它,因为它会打印 1 并为每次转换添加一个换行符。

【讨论】:

  • 所以基本上,我把什么对象作为那个参数都没有关系。只要它有一个合理的函数运算符,它应该可以工作?
【解决方案2】:

sequence(1,2) 不是构造函数调用,它是使用函数表示法的显式类型转换,导致 prvalue 类型为 sequence。这在 [expr.type.conv]/1 (N3337) 中有解释:

简单类型说明符 (7.1.6.2) 或类型名称说明符 (14.6) 后跟一个带括号的表达式列表构造一个给定表达式列表的指定类型的值。

[...]

如果表达式列表指定了多个值,则类型应为具有适当声明的构造函数(8.5, 12.1)的类,并且表达式 T(x1, x2, ...) 在效果上等同于声明 T t(x1, x2, ...);对于一些发明的临时变量 t,其结果是 t 的值作为纯右值。

sequence 可以作为int 接受的原因是它提供了到int 运算符的隐式转换:operator int

【讨论】:

    【解决方案3】:

    构造函数不返回任何东西意味着您不能手动设置返回值。但是,如果您在代码中使用 sequence(1, 2),它会创建您类型的临时对象。

    然后编译器尝试将该对象转换为int。既然你已经定义了int()操作符,那就成功了。

    【讨论】:

    • 所以它创建了一个临时对象,当fill 完成时,该对象被销毁。同时,函数运算符用于获取数字。我说得对吗?
    • 当您调用fill 时:首先创建sequence 对象,然后将其转换为int,将此int 值传递给fill,然后传递给sequence被破坏了。
    • @Heavy:不,sequence 对象被传递给填充函数,然后这个对象在函数内部一次又一次地转换,因为算法从 sequence 对象分配给每个输出范围的元素。
    • 该向量包含int 值,因此您不能只将随机对象传递给fill 函数。首先编译器将对象转换为int,然后将结果传递给函数。虽然也许你是对的,但这取决于实施。
    • 不,这是不正确的。 std::fill 的签名不允许这样做,因为没有检查迭代器的值类型。为什么你认为1 打印在 OP 输出的 7 行不同的行上?那就是转换运算符被调用了 7 次。
    【解决方案4】:

    当您调用sequence(1, 2) 时,为临时对象分配内存的不是ctor,而是编译器生成的代码。编译器生成的是这样的伪代码:

    sequence *tmp = allocate_memory_from_stack_for_temp_object();
    tmp->ctor(1, 2);
    return *tmp;
    

    正如您所见,ctor 正在处理现有内存,因此 ctor 函数不需要返回构造的对象。这是由 ctor 周围的一些逻辑处理的。当然编译器也会添加代码来销毁临时对象。

    【讨论】:

    • 所以我可以假设构造函数返回对对象的引用。我的假设是否正确?
    • 不,构造函数不返回任何内容。 sequence(1,2) 不是构造函数调用。
    • @elyasin 没有。ctor 不返回任何内容。正如 TartanLlama 在他的回答中所说的那样 sequence(1,2) 不是一个演员电话,它不仅如此。它是 tmp 对象的定义和对 tmp 对象的 ctor 的调用,表达式返回构造对象的值。
    【解决方案5】:

    在这里,您正在重载返回 int 的 operator()“函数调用运算符”。(将您的对象转换为 int)

    构造函数不返回任何内容,但通过使用仿函数(函数对象)您可以实现该场景。 (对不起,如果我在这里错了,任何人都让我知道你的 cmets)

    例如:假设我有 A 类。

    A obj(5);  // call to constructor.
    int b = obj(6);  // call to overloaded operator() that you need to define
    

    【讨论】:

    • 不,他在定义一个转换函数。这里没有重载或operator()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-28
    • 1970-01-01
    • 1970-01-01
    • 2015-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多