Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ “前应为类名”;{“标记”_C++ - Fatal编程技术网

C++ “前应为类名”;{“标记”

C++ “前应为类名”;{“标记”,c++,C++,到目前为止,我已经查找了大多数针对这种错误的典型解决方案,但似乎没有一个能与我的代码一起工作++ 问题类的结构如下。 m、 嗯 #ifndef M#H #定义M_H #包括“z.hh” #包括 #包括 使用名称空间std; M类:公共Z类 {/*编译器将此行标记为错误*/ 空m1(); 空隙m2(); }; #恩迪夫 m、 cpp #包括 #包括 #包括“m.hh” 使用名称空间std; void M::m1(){/*bla*/}; void M::m2(){/*bla*/}; } 编辑:

到目前为止,我已经查找了大多数针对这种错误的典型解决方案,但似乎没有一个能与我的代码一起工作++

问题类的结构如下。 m、 嗯

#ifndef M#H
#定义M_H
#包括“z.hh”
#包括
#包括
使用名称空间std;
M类:公共Z类
{/*编译器将此行标记为错误*/
空m1();
空隙m2();
};
#恩迪夫
m、 cpp

#包括
#包括
#包括“m.hh”
使用名称空间std;
void M::m1(){/*bla*/};
void M::m2(){/*bla*/};
}
编辑: z、 嗯

#ifndef Z#H
#定义Z_H
#包括“m.hh”
#包括
#包括
使用名称空间std;
Z类;
静态Z*s(字符串g、字符串i);
#恩迪夫
z、 cpp

#包括“z.hh”
#包括
#包括
Z类
{
公众:
第i串;
字符串g;
无效集_i(字符串im){i=im;}
字符串get_i(){return i;}
字符串get_g(){return g;}
虚空m1()=0;
虚空m2()=0;
Z*s(字符串g、字符串i){
Z*Z;
如果(g=“m”){
M*z=新的M;
}
}
};

谢谢

问题

不能从不完整的类型派生,这就是
m.hh
中的
Z
类型

从类型派生时,编译器必须知道所述类型的定义。试想一下,您正试图在类型为
M
的对象上从
Z
调用派生成员函数,而不知道
Z
是否实际声明了这样的成员,编译器如何知道这样的调用是否是有效的构造

还有一个更相关的问题,
M
如何能够在不知道
Z
是什么的情况下初始化
Z


解决方案


类Z
的定义移动到
Z.hh
,并将其成员函数的定义保留在
Z.cpp
中(与将
M
拆分为
M.hh
M.cpp
的方式相同)。

不能从不完整的类型派生,这就是
m.hh
中的
Z
类型

从类型派生时,编译器必须知道所述类型的定义。试想一下,您正试图在类型为
M
的对象上从
Z
调用派生成员函数,而不知道
Z
是否实际声明了这样的成员,编译器如何知道这样的调用是否是有效的构造

还有一个更相关的问题,
M
如何能够在不知道
Z
是什么的情况下初始化
Z


解决方案


类Z
的定义移动到
Z.hh
,并将其成员函数的定义保留在
Z.cpp
中(与在
M.hh
M.cpp
之间拆分
M
的方式相同)。

删除
\35;包括“M.hh”从
z.hh
中删除
#从
z.hh中删除“m.hh”
以修复循环包含。

那么,z.cpp文件实际上是一个类声明,应该是一个头文件。只有在处理指向该类的指针时,前向十分位才足够,但对于从一个类继承则不够(编译器确实需要知道z的类布局)

实际上并不需要z.hh,其中的函数声明也不是您所想的(它不是成员函数声明)。您可以删除它并将z.cpp重命名为z.hh

好的,与@Luchian Grigore的交流让我意识到你可能想要什么,以及为什么你有“两个z.hh”。Z将生成一个M,但M继承自Z,因此存在循环依赖关系。在C/C++中,打破这种循环的方法是限制一个类需要从另一个类知道什么:为了声明一个成员函数s,它生成一个指向新的MZ类声明的指针,只需要一个类型名M,而不是整个类声明的类型名M。因此,只需在Z的声明中引入类型名M的前向声明(
classm;
)就足够了;如果指向M对象的指针作为指向基Z的指针返回,则在声明Z时根本不需要M的名称


工厂函数的定义(无论是静态文件还是成员函数)需要,如果它要生成一个M,M的完整声明。这将在一个seapate cpp文件中,该文件将包含一个完整的头文件和M的完整声明。

好的,z.cpp文件实际上是一个类声明,应该是一个头文件。只有在处理指向该类的指针时,前向十分位才足够,但对于从一个类继承则不够(编译器确实需要知道z的类布局)

实际上并不需要z.hh,其中的函数声明也不是您所想的(它不是成员函数声明)。您可以删除它并将z.cpp重命名为z.hh

好的,与@Luchian Grigore的交流让我意识到你可能想要什么,以及为什么你有“两个z.hh”。Z将生成一个M,但M继承自Z,因此存在循环依赖关系。在C/C++中,打破这种循环的方法是限制一个类需要从另一个类知道什么:为了声明一个成员函数s,它生成一个指向新的MZ类声明的指针,只需要一个类型名M,而不是整个类声明的类型名M。因此,只需在Z的声明中引入类型名M的前向声明(
classm;
)就足够了;如果指向M对象的指针作为指向基Z的指针返回,则在声明Z时根本不需要M的名称

工厂函数的定义(无论是静态文件还是成员函数)需要,如果它要生成一个M,M的完整声明。那将是在一个s
#ifndef M_H
#define M_H

#include "z.hh"
#include <iostream>
#include <string>


using namespace std;

class M: public Z
{                        /* this line is marked by the compiler as errorneous */
void m1();
void m2();
};

#endif
#include <iostream>
#include <string>
#include "m.hh"

using namespace std;

void M::m1()                    {/*bla bla*/};
void M::m2()                        {/*bla bla*/};
}
#ifndef Z_H
#define Z_H

#include "m.hh"
#include <iostream>
#include <string>


using namespace std;

class Z;

static Z* s(string g, string i);

#endif
#include "z.hh"
#include <iostream>
#include <string>


class Z
{


public:
    string i;
    string g;

    void set_i(string im)                       {i = im;}
    string get_i()                              {return i;}
    string get_g()                          {return g;}
    virtual void m1()=0;
    virtual void m2()=0;
    Z* s(string g, string i)    {
        Z * z;
        if(g=="m"){
            M * z = new M;

        }
    }

};