下面是代码的两个片段(准备编译).在第一个片段中,我只使用结构的前向声明,同时从Guest类删除指向此结构的指针,不调用Guest类.
在第二个片段中,而不是前向声明我使用基本工作中的删除使用此Guest类的完整定义.
为什么?为什么会有所作为?是不是前向声明假设只是编译器的一个注释,说这个类/结构的定义在其他地方?
我很惊讶它只是不直观地工作.
//First just forward dclr
#include "stdafx.h"
#include <iostream>
using std::cout;
struct Guest;
struct Base
{
Guest* ptr_;
Base(Guest* ptr):ptr_(ptr)
{
cout << "Base\n";
}
~Base()
{
cout << "~Base\n";
delete ptr_;
}
};
struct Guest
{
Guest()
{
cout << "Guest\n";
throw std::exception();
}
Guest(int)
{
cout << "Guest(int)\n";
}
~Guest()
{
cout << "~Guest\n";
}
};
struct MyClass : Base
{
Guest g;
MyClass(Guest* g):Base(g)
{
cout << "MyClass\n";
}
~MyClass()
{
cout << "~MyClass\n"; …Run Code Online (Sandbox Code Playgroud) 由于我最近有一个导入循环,我将所有#import语句(关于我自己的文件)从标题移动到相应的.m-file中.我还添加了@class与@protocol前瞻性声明,以安抚编译器.但是,我仍然听到他的警告:
Cannot find the protocol definition for 'MyCustomDelegate'.
Run Code Online (Sandbox Code Playgroud)
正如我所说,@protocol MyCustomDelegate之前我在@interface-Block中使用它.有趣的是,只有在另一个文件中声明相应的委托(其标头在.m-file中导入)时,才会出现此警告.
我读到一个解决方案是在单独的头文件中声明委托,并直接在实现委托的类的头中导入该文件.这真的是要走的路吗?还有其他解决方案吗?我认为那些代表已经充分夸大了我们的代码,现在我应该继续甚至为它声明一个自己的文件?
小样本代码可以更好地说明问题:
NewFooController.h
#import <UIKit/UIKit.h>
@protocol NewFooControllerDelegate;
@interface NewFooController : UITableViewController
@property (nonatomic, weak) id<NewFooControllerDelegate> delegate;
@end
@protocol NewFooControllerDelegate
@end
Run Code Online (Sandbox Code Playgroud)
HomeTableViewController.h
#import <UIKit/UIKit.h>
@protocol NewFooControllerDelegate;
// warning points to line below
@interface HomeTableViewController : UITableViewController <NewFooControllerDelegate>
@end
Run Code Online (Sandbox Code Playgroud)
HomeTableViewController.m
#import "HomeTableViewController.h"
#import "NewFooController.h"
@implementation HomeTableViewController
@end
Run Code Online (Sandbox Code Playgroud) 根据7.3.1.2 C++标准ISO/IEC 14882:2003(E)中的命名空间成员定义
首先在名称空间中声明的每个名称都是该名称空间的成员.如果非本地类中的友元声明首先声明一个类或函数(这意味着该类或函数的名称是不合格的),那么友元类或函数是最内层封闭命名空间的成员.
// Assume f and g have not yet been defined.
void h(int);
template <class T> void f2(T);
namespace A {
class X {
friend void f(X); // A::f(X) is a friend
class Y {
friend void g(); // A::g is a friend
friend void h(int); // A::h is a friend
// ::h not considered
friend void f2<>(int); // ::f2<>(int) is a friend
};
};
// A::f, A::g and A::h are not visible here
X x;
void …Run Code Online (Sandbox Code Playgroud) 假设有两个类,它们需要彼此:容器和项目.类容器创建类项的实例.类项的每个实例都包含一个类容器的实例,只需要调用类容器的方法method_called_by_item.类容器需要查看类项的所有字段.
问题是前向声明:我想在item.h中有一个前向声明,这样类项可以有一个容器作为字段并调用方法method_called_by_item.我怎么做?
类容器,用于创建项目.
// container.h
#ifndef CONTAINER_H
#define CONTAINER_H
#include "item.h"
class container{
public:
item * create_item();
void method_called_by_item(item * i);
};
#endif //CONTAINER_H
Run Code Online (Sandbox Code Playgroud)
实施:
// container.cpp
#include "container.h"
item * container::create_item(){
return new item(this);
}
void container::method_called_by_item(item * i){
// do stuff with item
}
Run Code Online (Sandbox Code Playgroud)
类项,需要调用一个容器 …
我在SBCL中编写了一些代码,当我将文件加载到REPL中时,我的函数的顺序一直会导致出现以下类型的警告:
;caught STYLE-WARNING:
undefined function: FOO
Run Code Online (Sandbox Code Playgroud)
FOO函数的符号在哪里.这纯粹是因为他们是如何在我的文件排序,作为函数FOO 的定义,只是没有抛出这一警告的代码部分之前.
现在,在Clojure中,我熟悉的是Lisp,我有一个declare表单,它允许我做出前瞻性声明以避免这种问题.SBCL/Common Lisp总体上有类似的东西吗?
也许有人知道,是否可以在特征中转发声明类型MatrixXd & VectorXd?
\n\n编译时,我收到以下错误:
\n\n/usr/include/eigen3/Eigen/src/Core/Matrix.h:372:34: 错误:声明冲突 \xe2\x80\x98typedef 类 Eigen::Matrix Eigen::MatrixXd\xe2\x80\x99
\n\ntypedef Matrix Matrix##SizeSuffix##TypeSuffix;
\n\nSIMP.h
\n\n#ifndef SIMP_H\n#define SIMP_H\n\n\nnamespace Eigen\n{\n class MatrixXd;\n class VectorXd;\n}\n\nclass SIMP {\npublic:\n SIMP(Eigen::MatrixXd * gsm, Eigen::VectorXd * displ);\n SIMP ( const SIMP& other ) = delete;\n ~SIMP(){}\n SIMP& operator= ( const SIMP& other ) = delete;\n bool operator== ( const SIMP& other ) = delete;\n\n\nprivate: \n Eigen::MatrixXd * m_gsm;\n Eigen::VectorXd * m_displ;\n\n};\n\n#endif // SIMP_H\nRun Code Online (Sandbox Code Playgroud)\n\nSIMP.cpp
\n\n#include "SIMP.h"\n#include <Eigen/Core>\nSIMP::SIMP( Eigen::MatrixXd …Run Code Online (Sandbox Code Playgroud) 请考虑以下代码段,其中第一行仅用作前向声明
class A;
Run Code Online (Sandbox Code Playgroud)
然后定义新类
class B
{
vector<A> Av; //line 1
map<int, A> Am; //line 2
pair<int, A> Ap; //line 3
};
Run Code Online (Sandbox Code Playgroud)
第1行和第2行似乎没有前向声明(这可能告诉我那些容器使用指针类型的实现),其中第3行似乎不在VS2012上编译.
我的问题是标准或特定于我正在使用的编译器所规定的行为?
谢谢
正如这个答案所暗示的那样,我知道允许在函数声明中使用不完整类型作为返回值.所以我写了下面的代码:
Obj.h
class Obj {
int x;
};
Run Code Online (Sandbox Code Playgroud)
FH
class Obj;
Obj f();
Run Code Online (Sandbox Code Playgroud)
f.cpp
#include "Obj.h"
Obj f() {
return Obj();
}
Run Code Online (Sandbox Code Playgroud)
main.cpp中
#include "f.h"
int main() {
f();
return 0;
};
Run Code Online (Sandbox Code Playgroud)
使用以下编译器编译此代码:
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
使用以下编译命令:
g++ *.cpp
Run Code Online (Sandbox Code Playgroud)
给出以下错误:
main.cpp: In function 'int main()':
main.cpp:4:7: error: invalid use of incomplete type 'class Obj'
f();
^
f.h:1:7: error: forward declaration of 'class Obj'
class Obj;
^
Run Code Online (Sandbox Code Playgroud)
因此编译器不允许在函数声明中使用不完整类型作为返回值.解释是什么?
首先在 elaborated-type-specifier中声明的类的声明要点如下:
(7.1)声明形式
class-key attribute-specifier-seq opt 标识符
;的识别符被声明为一个类名称在包含声明的范围,否则
(7.2)用于阐述型说明符的形式的
类键 标识符
如果在命名空间范围内定义的函数的decl-specifier-seq 或parameter-declaration-clause中使用了elaborated-type-specifier,则标识符将在包含该声明的命名空间中声明为类名;否则,除作为好友声明外,标识符在包含该声明的最小名称空间或块范围中声明。[?注意:这些规则也适用于模板。-?end note?] [?注:其他形式的 elaborated-type-specifier不会声明新名称,因此必须引用现有的type-name
。请参阅[basic.lookup.elab]和[dcl.type.elab]。-?尾注?]
考虑上面的情况(7.2),其中在命名空间范围中定义的函数的参数声明子句的decl-specifier-seq中使用了elaborated-type-specifier。这个精巧的类型说明符必须是该类在其命名空间中的第一个声明,这一事实如何与之相协调?
考虑下面的示例(demo):
档案prog.cc:
struct S;
extern S s;
int S;
void f(struct S&); // The elaborated-type-specififer `struct S` is not
// the first …Run Code Online (Sandbox Code Playgroud) 所以,我在一个文件中有这两个数据类:
@dataclass
class A:
children: List[B]
@dataclass
class B:
parent: A
Run Code Online (Sandbox Code Playgroud)
,这可以通过使用该__future__.annotations功能来实现。
然后我有另外两个文件,每个文件都有一堆对于我的项目来说是静态的每种类型的对象。
文件objects_A:
import objects_B
obj_a1 = A(
children=[
objects_B.obj_b1,
objects_B.obj_b2
]
)
Run Code Online (Sandbox Code Playgroud)
文件objects_B:
import objects_A
obj_b1 = B(
parent=objects_A.obj_a1
)
obj_b2 = B(
parent=objects_A.obj_a1
)
Run Code Online (Sandbox Code Playgroud)
显然,文件之间存在循环依赖问题,但即使它们位于同一个文件中,它也不起作用,因为一种类型的变量依赖于另一种类型的变量才能成功。
初始化B内部对象obj_a1也不起作用,因为self这里没有概念。
目前,我设置parent为None(针对类型提示),然后循环进行设置obj_a1:
for obj_b in obj_a1.children:
obj_b.parent = obj_a1
Run Code Online (Sandbox Code Playgroud)
大家有什么好主意吗?
不知道它是否有帮助,但是这些对象是静态的(它们在这些声明之后不会改变)并且它们具有某种父子关系(正如您肯定已经注意到的那样)。
如果可能的话,我希望将每种类型的变量放在不同的文件中。
python forward-declaration circular-reference python-3.x python-dataclasses
c++ ×7
eigen ×1
friend ×1
namespaces ×1
objective-c ×1
protocols ×1
python ×1
python-3.x ×1
sbcl ×1
std-pair ×1
stl ×1
xcode ×1