【问题标题】:class type conversion fails C++类类型转换失败 C++
【发布时间】:2015-06-10 16:42:06
【问题描述】:

我正在尝试编译某些东西,但它不会,而且我在网络上找不到任何相关内容。

#include<iostream>
using namespace std;

class A;
class B
{
    int x;
public:
    B(int i=107) {x=i;}
    operator A();
};
B::operator A() {return x;}

class A
{
    int x;
public:
    A(int i=6) {x=i;}
    int get_x() {return x;}
};

int main()
{
    A a;
    B b=a;
    cout<<a.get_x();
    return 0;
}

我得到错误: 返回类型“A 类”不完整 请求从“A”转换为非标量类型“B”

即使这样也行不通:

    B B;
    A a=b;

我不知道自己做错了什么,也不知道在哪里可以找到有关该主题的更多信息。

谢谢

【问题讨论】:

  • B::operator A() {return x;} 移动到class A 之后。那就是`'A类'的本质是不完整的`
  • 谢谢。但是我想知道为什么 A 类的前向声明不起作用?
  • 如果不首先重载 = 运算符,则无法使用 = 将对象从 B 类转换为 A 类。
  • @IleanaProfeanu 你有B类上面的前向声明,但是下面的实际定义,所以B类甚至不知道A类是什么。前向声明通常用在头文件中。如果您将 B 类移到 A 类下方,则不需要前向声明。
  • @CNomad 在这种情况下,复制构造函数被调用,所以即使没有重载也可以使用'='

标签: c++ type-conversion incomplete-type


【解决方案1】:

您没有发布错误的全文,这意味着您遗漏了所有重要的行号。通常情况下,行号通常是错误中最有价值的信息。

class A;
class B
{
    ...
};
B::operator A() {return x;}

我猜这是你的编译器告诉你错误发生的那一行。

在这行代码中,编译器还没有完整的A 声明,因此它不知道如何将int x 转换为class A。 C++ 编译是单程的,所以它不能推迟这个查找。

在继续定义之前,您需要完成声明。

class A;
class B
{
    int x;
public:
    B(int i=107) {x=i;}
    operator A();
};

class A
{
    int x;
public:
    A(int i=6) {x=i;}
    int get_x() {return x;}
};

// done with declarations. begin definitions.

B::operator A() {return x;}
// compiler quietly expands this to be:
// B::operator A() { return A::A(i=this->x); }

通常AB 将位于头文件中,并且您将保留定义,这需要完全声明两个类以用于某个 .cpp 文件。

【讨论】:

    【解决方案2】:

    代码有几个问题(参见 cmets)

    #include<iostream>
    
    // Side Note: Never do this in a header (I avoid it in sources, too)
    using namespace std;
    
    class A;
    class B
    {
        int x;
    public:
        B(int i=107) {x=i;}
        operator A() const;
        // Moved to make 'main' reasonable
        int get_x() {return x;}
    };
    
    class A
    {
        int x;
    public:
        A(int i=6) {x=i;}
        // Make the desired conversion work:
        operator B () const { return x; }
    };
    
    // This nedds a complete A. In other words, the delaration of A has to be knonwn.
    B::operator A() const {return x;}
    
    
    int main()
    {
        A a;
        B b=a;
        cout << b.get_x() << '\n';
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      您可以轻松地将 B 类的声明移到 A 类的声明下方。

      class A
      {
          ...
      };
      
      class B
      {
          ...
          operator A();
      };
      B::operator A() {return x;}
      

      并且不要使用前向声明。然后像这样使用运算符,因为您不是将 A 转换为 B,而是将 B 转换为 A。

      B b;
      A a = b; // A a = (A)b;
      ...
      

      关于发生了什么,我添加了一些打印以显示代码经过的位置,

      A(int i=6) {
          std::cout<<"Created A"<<std::endl;x=i;
      }
      A( const A& a ) {
          std::cout<<"Created A by Copy"<<std::endl;
          this->x = a.x;
      }
      B::operator A() {
          std::cout << "Operator A" << std::endl;
          return x;
      }
      

      然后运行这个,

      B b;
      std::cout << "Begin" << std::endl;
      A a = b;
      std::cout << "End" << std::endl;
      ...
      

      这是输出,

      Begin
      Operator A
      Created A
      Created A by copy
      End
      

      所以运算符 A 返回一个 int,它用于构造 A 的实例,然后用于通过复制初始化实例 'a'。我从来不知道你可以做这样的事情(你可能不想这样做,但是是的..)

      编辑:您实际上应该在运算符 A() 中显式创建 A 的实例,而不是依赖编译器。

      【讨论】:

        猜你喜欢
        • 2014-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多