默认参数和前向声明
Default parameters and forward declaration
我有一个 class Property
和一个我想要默认参数的构造函数,在文件 property.h
:
class Property {
Property(OtherClass* value = myApp->someValue) {...};
};
其中另一种类型 Application
的 myApp
是在广泛使用此 属性 class 的另一个文件中定义的。由于这个其他文件#includes property.h,当然,我不能#include 这个文件在property.h
property.h
不知道 myApp
和 Application
(尽管 property.cpp
知道,并且 OtherClass
在 property.h
中已知)。
我可以转发声明 OtherClass
并将 myApp
声明为 extern
,但这会导致错误 C2027“使用未定义类型的应用程序”,正如预期的那样:
class Application;
extern Application* myApp;
class Property {
Property(OtherClass* value = myApp->someValue) {...};
};
一个解决方案可能是在 .cpp 文件中使用默认参数,但这是不可取的 (here)。
如何让这个默认参数起作用? (即,不是另一种解决方案不涉及没有默认参数告诉我默认参数是邪恶的,或者我的设计开始时很糟糕等;))。谢谢!
值得注意的是,函数参数的默认参数在调用函数的地方解析(与定义函数的位置相反)。这给出了必要的 space 来解决 OPs 问题 yet another level of indirection:
代替访问myApp->someValue
,引入了一个辅助函数,可以在Property
定义之前声明,但在Application
完全定义之后实现。 (这也可以是 Property
的 static
成员函数。)
演示示例:
#include <iostream>
int getAppDefault();
struct Application;
extern Application *pApp;
struct Property {
int value;
Property(int value = getAppDefault()): value(value) { }
};
struct Application {
int valueDefault = 123;
};
Application app;
Application *pApp = &app;
int getAppDefault() { return pApp->valueDefault; }
int main()
{
Property prop1;
std::cout << "prop1: " << prop1.value << '\n';
app.valueDefault = 234;
Property prop2;
std::cout << "prop2: " << prop2.value << '\n';
}
输出:
prop1: 123
prop2: 234
为了强调 value = getAppDefault()
实际上是在调用构造函数 Property::Property()
时解析的,我在默认构造 prop2
之前修改了 Application::valueDefault
。
当然,如果 Property
存储的是指针而不是值本身,这也适用:
首先,要使用 Application
class 的成员,您 必须 具有 Application
class。否则编译器将不知道 class.
的成员
其次,您可能应该使 Property
构造函数 explicit
禁止从 Application
进行隐式转换。这种隐式转换往往会使代码更难阅读、理解和维护。
第三,作为解决第一个问题的一种可能方法,您可以使用 重载 来拥有两个 Property
构造函数:一个具有非默认 Property*
参数,还有一个根本没有任何参数。无参数构造函数委托给单参数构造函数进行初始化。这种拆分成两个构造函数将使定义(实现)与声明分开变得更容易。
在代码中,我的解决方案如下所示:
首先是Property
头文件
// Forward declaration only, no header file needed
class OtherClass;
class Property
{
public:
Property();
explicit Property(OtherClass* other);
// ...
};
然后Property
class源文件
#include "Property.h"
// Get the full and complete definition of the Application class
#include "Application.h"
extern Application* myApp;
// Will probably need the full definition of the OtherClass as well
#include "OtherClass.h"
// Default constructor delegates to one-argument constructor
Property::Property()
: Property{ myApp->GetOtherObject() }
{
}
Property::Property(OtherClass* other)
{
// Use the other class here...
}
我有一个 class Property
和一个我想要默认参数的构造函数,在文件 property.h
:
class Property {
Property(OtherClass* value = myApp->someValue) {...};
};
其中另一种类型 Application
的 myApp
是在广泛使用此 属性 class 的另一个文件中定义的。由于这个其他文件#includes property.h,当然,我不能#include 这个文件在property.h
property.h
不知道 myApp
和 Application
(尽管 property.cpp
知道,并且 OtherClass
在 property.h
中已知)。
我可以转发声明 OtherClass
并将 myApp
声明为 extern
,但这会导致错误 C2027“使用未定义类型的应用程序”,正如预期的那样:
class Application;
extern Application* myApp;
class Property {
Property(OtherClass* value = myApp->someValue) {...};
};
一个解决方案可能是在 .cpp 文件中使用默认参数,但这是不可取的 (here)。
如何让这个默认参数起作用? (即,不是另一种解决方案不涉及没有默认参数告诉我默认参数是邪恶的,或者我的设计开始时很糟糕等;))。谢谢!
值得注意的是,函数参数的默认参数在调用函数的地方解析(与定义函数的位置相反)。这给出了必要的 space 来解决 OPs 问题 yet another level of indirection:
代替访问myApp->someValue
,引入了一个辅助函数,可以在Property
定义之前声明,但在Application
完全定义之后实现。 (这也可以是 Property
的 static
成员函数。)
演示示例:
#include <iostream>
int getAppDefault();
struct Application;
extern Application *pApp;
struct Property {
int value;
Property(int value = getAppDefault()): value(value) { }
};
struct Application {
int valueDefault = 123;
};
Application app;
Application *pApp = &app;
int getAppDefault() { return pApp->valueDefault; }
int main()
{
Property prop1;
std::cout << "prop1: " << prop1.value << '\n';
app.valueDefault = 234;
Property prop2;
std::cout << "prop2: " << prop2.value << '\n';
}
输出:
prop1: 123
prop2: 234
为了强调 value = getAppDefault()
实际上是在调用构造函数 Property::Property()
时解析的,我在默认构造 prop2
之前修改了 Application::valueDefault
。
当然,如果 Property
存储的是指针而不是值本身,这也适用:
首先,要使用 Application
class 的成员,您 必须 具有 Application
class。否则编译器将不知道 class.
其次,您可能应该使 Property
构造函数 explicit
禁止从 Application
进行隐式转换。这种隐式转换往往会使代码更难阅读、理解和维护。
第三,作为解决第一个问题的一种可能方法,您可以使用 重载 来拥有两个 Property
构造函数:一个具有非默认 Property*
参数,还有一个根本没有任何参数。无参数构造函数委托给单参数构造函数进行初始化。这种拆分成两个构造函数将使定义(实现)与声明分开变得更容易。
在代码中,我的解决方案如下所示:
首先是Property
头文件
// Forward declaration only, no header file needed
class OtherClass;
class Property
{
public:
Property();
explicit Property(OtherClass* other);
// ...
};
然后Property
class源文件
#include "Property.h"
// Get the full and complete definition of the Application class
#include "Application.h"
extern Application* myApp;
// Will probably need the full definition of the OtherClass as well
#include "OtherClass.h"
// Default constructor delegates to one-argument constructor
Property::Property()
: Property{ myApp->GetOtherObject() }
{
}
Property::Property(OtherClass* other)
{
// Use the other class here...
}