【问题标题】:Questions about a piece of code with templates, conversion operator and copy ctor关于带有模板、转换运算符和复制 ctor 的一段代码的问题
【发布时间】:2016-01-30 21:47:00
【问题描述】:

关于下面这段代码的两个问题:

template <class T> class A {
protected:
    T j;
public:
    A(T k) :j(k) {cout << *this;}
    ~A() { cout << *this; }
    A(const A<T> &a) {
        j = a.j;
        cout << *this;
    }
    virtual void print() const {cout << j << ' ';}

    friend ostream &operator << (ostream &os, const A<T> &a) {
        a.print();
        return os;
    }
    operator T() {  return j;}
};

template <class T> class inherit:public A<T> {
    T field;
public:
    inherit(const T&t) :A<T>(t), field(1+t) {
        cout << *this;
    }
    void print() const {
        A<T>::print();
        cout << field << ' ';
    }
};
int main(){
    inherit <int> b(3);

    inherit <string> c("asdf");
    string k="str";
    c + k;//error no operator +
    b + 5;//no error
}
  1. 为什么inherit &lt;int&gt; b(3); 会导致inherit 的复制ctor?为什么要使用默认 ctor 从头开始​​复制而不是创建 inherit 的新实例?

  2. 为什么b+5; 会导致转换运算符operator T() 以及为什么c+k 不会发生?

【问题讨论】:

  • main 必须在 C++ 中返回 int
  • b+5 有效,因为5 是一个 int 并且有一个内置的 operator+string 是一个模板,模板化的operator+ 都不匹配inherit&lt;string&gt;string
  • 但是operator+@BoPersson也内置了string,为什么还要用b+5;进行转换?
  • @kuh 看看operator+ 上的std::basic_string 是如何定义的。也让我们偷懒:包括令人惊讶的输出(应该是全部),你认为它意味着什么,以及你明确期望什么。我的心理 C++ 编译器不完善,复制/粘贴/编译是可行的。
  • field(1+t) 导致 inherit&lt;string&gt; 甚至无法为我编译。你能确保你的例子可以编译吗?用魔杖盒?

标签: c++ templates c++11 operator-overloading copy-constructor


【解决方案1】:
  1. 为什么inherit &lt;int&gt; b(3);会导致继承的copy ctor?为什么要复制而不是使用默认 ctor 从头开始​​创建一个新的继承实例?

首先,它不会导致复制构造函数,并且实例实际上是从头开始制作的

没有使用默认构造函数,因为您没有调用默认构造函数。默认构造函数将使用空参数列表调用(除了在这种情况下,您还必须省略括号以避免令人烦恼的解析):

inherit <int> b; // this would call the default constructor

如果将参数传递给构造函数,则将调用非默认构造函数。 inherit &lt;int&gt; b(3); 导致对inherit(const T&amp;) 的调用,在此模板实例中为inherit(const int&amp;)。不是inherit的拷贝构造函数。

  1. 为什么 b+5;导致转换运算符 operator T()

因为没有operator+(const inherit&lt;int&gt;&amp;, int) 也没有定义类似的成员函数。因此,重载决议会寻找可以隐式转换操作数的替代方案。碰巧的是,存在一个内置的operator+(int, int),并且inherit&lt;int&gt; 可以隐式转换为A&lt;int&gt;(因为它是一个基础),A&lt;int&gt; 可以转换为int(因为铸造操作员)。因此,该运算符最终被调用。

为什么 c+k 不会发生这种情况?

首先,您甚至无法实例化 inherit &lt;string&gt;,因为构造函数试图将 int 添加到没有有效重载的参数字符串中。

现在,假设构造函数已修复,inherit&lt;string&gt; 可以存在,c + k 似乎仍然不起作用。我怀疑这是因为字符串需要比int 更多的转换,因为它不是原始的,并且您已经达到了用户定义的转换序列可以具有的最大深度。您可以将inherit&lt;string&gt; 显式转换为string 以缩短转换序列:

static_cast<std::string>(c) + k; // this works

【讨论】:

  • 在他的 c+k 示例中,cinherit&lt;string&gt;,而不是 inherit&lt;int&gt;
  • 为什么是operator+(const std::string&amp;, int)cinherit &lt;string&gt;k 是一个字符串。
  • @kuhaku & Billy,我最初读错了代码。答案固定。
  • inherit(const T&amp; t) 如果是 inherit(const inherit&amp; t) 会是一个复制 ctor?
【解决方案2】:
  1. 为什么 b+5;导致转换运算符 operator T() 以及为什么它不会发生在 c+k 中?

编译器抱怨一段完全不同的代码。如果你去掉main()里面的+,你可以看到它仍然在抱怨operator+

http://melpon.org/wandbox/permlink/H3cUUaf8fSnbYDwA

原因就在这一行:

inherit(const T&t) :A<T>(t), field(1+t) {

你有1 + t,其中tstd::stringstd::string 没有int 的运算符+,因此无法编译。

【讨论】:

  • 它也可以在 VS15 上编译:coliru.stacked-crooked.com/a/b07a46a2cd6a28bf
  • @kuhaku:它编译是因为您注释掉了inherit&lt;string&gt;,而不是因为您注释掉了main 中的+ 语句。如果您在堆积弯曲的示例中取消注释第 46 行,它将无法编译。
  • 虽然这个错误使 kuhaku 的示例代码很糟糕,但有趣的是,如果您修复构造函数,代码确实会重现所询问的行为。 c+k 没有找到过载。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-05
  • 1970-01-01
  • 2021-03-07
相关资源
最近更新 更多