我是Javascript的新手,并对函数声明的工作方式感到困惑.我对此做了一些测试并得到了一些有趣的结果:
say();
function say()
{
alert("say");
}
Run Code Online (Sandbox Code Playgroud)
前进声明工作和弹出"说"
相反
say();
say = function()
{
alert("say");
}
Run Code Online (Sandbox Code Playgroud)
没有工作,虽然它也声明了一个函数对象
如果我们声明该函数并在之后重新声明:
function say()
{
alert("speak");
}
say();
function say()
{
alert("say");
}
Run Code Online (Sandbox Code Playgroud)
我得到"说"而不是"说话".这太令人惊讶了!
好.似乎只有最新的函数声明才有效.然后让我们首先声明函数对象,然后是"常规"函数:
say = function()
{
alert("speak");
}
say();
function say()
{
alert("say");
}
say();
Run Code Online (Sandbox Code Playgroud)
另一个惊喜,是"说话",然后是"说话"."常规"功能声明根本不起作用!
是否有所有这些的解释?并且,如果"常规"函数声明真的是"脆弱的"并且可以通过具有相同名称的函数对象轻松覆盖,那么我应该远离那个吗?
另一个问题是:只使用函数对象格式,前向声明是否变得不可能?有没有办法在Javascript中"模拟"它?
在Effective C++(第3版)中,Scott Meyers在第31项中建议,除了经典的声明(.h)和定义(.cpp)文件之外,类应该具有前向声明包含文件(fwd.h),哪个类不需要完整定义可以使用,而不是向前声明自己.
我有点看到它的情况,但我真的不认为这是一个可行的选择...它似乎很难维持,相当矫枉过正,几乎没有必要.
但是,我可以看到它用于模板前向声明,它相当重.但对于简单的课程?这似乎很难维护,并且会创建一大堆几乎空的包含文件,这些文件只是用于非常小的目的......值得麻烦吗?
这是一个例子:
// Class.h
class Class
{
Class();
~Class();
};
// ClassFwd.h
class Class;
// Class.cpp
Class::Class()
{
}
Class::~Class()
{
}
Run Code Online (Sandbox Code Playgroud)
我的问题:
你们有什么感想?如果这是一个很好的做法?
注意我最感兴趣的是这个练习的论据,看看我是否错过了一些让我同意Scott Meyers的内容.
我知道循环依赖,但即使使用前向声明,我也会得到这个区域.我究竟做错了什么?
// facility.h
class Area;
class Facility {
public:
Facility();
Area* getAreaThisIn();
void setAreaThisIsIn(Area* area);
private:
Area* __area;
};
// facility.cpp
#include "facility.h"
#include "area.h"
{ ... }
// area.h
class Facility;
class Area {
public:
Area(int ID);
int getId();
private:
std::list<Facility*> _facilities;
};
// area.cpp
#include "area.h"
#include "facility.h"
Run Code Online (Sandbox Code Playgroud)
所以这个编译很好,但如果我这样做
// foo.h
#include "facility.h"
class Foo { .. };
// foo.cpp
#include "foo.h"
void Foo::function() {
Facility* f = new Facility();
int id = f->getAreaThisIsIn()->getId();
Run Code Online (Sandbox Code Playgroud)
当我得到 invalid use of …
我有两节课,foo和bar.
foo.h #includes bar.h并包含一个std::vector指向bar对象的指针.在运行时期间的某个时刻,bar必须访问指向其他bar对象的指针向量.因此,foo包含一个getBarObjects()返回指针数组的方法.
因此,我foo在bar.h中转发声明.我显然还要转发声明我正在使用的方法 - foo::getBarObjects().当这返回指针数组时bar,我陷入了恶性循环.
我无法转发声明Bar然后只是转发声明getBarObjects(),因为这导致"不允许不完整的类型名称".
foo.h中:
#include "bar.h"
#include <vector>
class foo {
public:
foo();
~foo();
std::vector<bar*> getBarObjects();
private:
std::vector<bar*> barObjects;
}
Run Code Online (Sandbox Code Playgroud)
bar.h:
class foo;
std::vector<bar*> foo::getBarObjects(); // error, doesn't know bar at this point
class bar {
public:
bar(foo *currentFoo);
~bar();
bool dosth();
private:
foo *thisFoo;
}
Run Code Online (Sandbox Code Playgroud)
bar.cpp:
#include "bar.h"
bool bar(foo …Run Code Online (Sandbox Code Playgroud) 如果我有一个不需要在.hpp文件中完整定义的类,我通常主要使用前向声明
例)
//B.hpp
namespace A_file {
class A;
}
namespace B_file {
class B {
public:
B();
private:
A *ptr_to_A;
}
}
//B.cpp
#include "A.hpp"
using namespace A_file;
namespace B_file {
B(int value_) {
*ptr_to_A = new A(value_);
}
int some_func() {
ptr_to_A->some_func_in_A();
}
}
Run Code Online (Sandbox Code Playgroud)
我写这种代码.我想,它将再次包括整个hpp.(随意评论,如果你的事情,这是不健康的)
有没有办法可以对std命名空间中的对象/类做同样的事情?如果有办法,可以,还是有副作用?
是否可以在m文件中使用函数,该文件在同一文件的后续部分中实现:与其他编程语言(如C)类似?
我有两个需要了解彼此成员的课程.
在C++中,我使用前向声明.
打字稿需要做什么?
以下代码编译并给出结果(GCC和clang):
template <typename T> struct Derived;
struct Base
{
template <typename T>
void foo(T * const t)
{
dynamic_cast<Derived<T> * const>(this)->bar(t);
}
};
template <typename T>
struct Derived : Base
{
void bar(T const *) const { }
};
Run Code Online (Sandbox Code Playgroud)
代码调用fooin Base到barin Derived.
作为参考,以下代码无法编译:
struct Derived2;
struct Base2
{
template <typename T>
void foo(T * const t)
{
dynamic_cast<Derived2 * const>(this)->bar(t);
}
};
struct Derived2 : Base2
{
template <typename T>
void bar(T const *) …Run Code Online (Sandbox Code Playgroud) 并不是说谷歌风格指南是神圣的圣经,但作为一个新手程序员,它似乎是一个很好的参考.
Google样式指南列出了前向声明的以下缺点
前向声明可以隐藏依赖项,允许用户代码在标题更改时跳过必要的重新编译.
随后对库的更改可能会破坏前向声明.函数和模板的前向声明可以防止标题所有者对其API进行其他兼容的更改,例如扩展参数类型,添加具有默认值的模板参数或迁移到新的命名空间.
从名称空间std ::转发声明符号会产生未定义的行为.
可能很难确定是否需要前向声明或完整#include.用前向声明替换#include可以默默地改变代码的含义:
码:
// b.h:
struct B {};
struct D : B {};
// good_user.cc:
#include "b.h"
void f(B*);
void f(void*);
void test(D* x) { f(x); } // calls f(B*)
Run Code Online (Sandbox Code Playgroud)
如果#include被B和D的forward decls替换,test()将调用f(void*).
从标题中声明多个符号的前向可能比简单地#include the header更加冗长.
构造代码以启用前向声明(例如,使用指针成员而不是对象成员)可以使代码更慢,更复杂.
然而,对SO的一些搜索似乎表明,前向声明通常是更好的解决方案.
因此,鉴于这些看似非平凡的缺点,有人可以解释这种差异吗?
什么时候忽略部分或全部这些缺点是安全的?
下面的代码片段演示了我最近在程序中遇到的一个实际问题:
#include<vector>
class A;
void f( const std::vector<A> & = {} );
Run Code Online (Sandbox Code Playgroud)
有一个不完整的类A和一个带有空默认值的vector函数声明。A而且该函数甚至没有在任何地方被调用。
它在 GCC 和 Clang 14 中工作正常,但从 Clang 15 开始出现错误:
In file included from <source>:1:
/opt/compiler-explorer/clang-15.0.0/bin/../include/c++/v1/vector:540:52: error: arithmetic on a pointer to an incomplete type 'A'
{return static_cast<size_type>(__end_cap() - this->__begin_);}
~~~~~~~~~~~ ^
/opt/compiler-explorer/clang-15.0.0/bin/../include/c++/v1/vector:760:56: note: in instantiation of member function 'std::vector<A>::capacity' requested here
__annotate_contiguous_container(data(), data() + capacity(),
^
/opt/compiler-explorer/clang-15.0.0/bin/../include/c++/v1/vector:431:7: note: in instantiation of member function 'std::vector<A>::__annotate_delete' requested here
__annotate_delete();
^
<source>:5:32: note: in …Run Code Online (Sandbox Code Playgroud) c++ forward-declaration stdvector language-lawyer incomplete-type
c++ ×7
function ×2
class ×1
declaration ×1
include ×1
javascript ×1
matlab ×1
std ×1
stdvector ×1
templates ×1
typescript ×1