如何在c++中返回NULL对象
How to return NULL object in C++
我知道这可能是:Return a " null;对象
但是,我的代码发生了一些不同的事情,因为星号不能解决我的问题,这是:
Normal Sphere::hit(Ray ray) {
//stuff is done here
if(something happens) {
return NULL;
}
//other stuff
return Normal(something, somethingElse);
}
但我得到一个错误引用return NULL
行:conversion from ‘int’ to non-scalar type ‘Normal’ requested
和另一个错误和警告,引用最后返回行:warning: taking address of temporary
和conversion from ‘Normal*’ to non-scalar type 'Normal' requested
我明白为什么我得到这个警告,但我不知道如何修复它。我如何在函数结束后持续的最后一行返回Normal
对象,以及我如何第一次返回NULL
对象?(如果有关于这些类型的回报的术语,请告诉我,以便我也可以更多地了解它。)
为了澄清评论者的问题,我尝试了以下方法:
我试着这样做:Normal *Sphere::hit(Ray ray)
在cpp文件和Normal *hit( Ray ray );
在头文件,我得到这个错误:error: prototype for ‘Normal* Sphere::hit(Ray)’ does not match any in class 'Sphere'
我还尝试了这个:cpp文件中的Normal Sphere::*hit(Ray ray)
和头文件中的Normal *hit( Ray ray);
,我得到第二个返回语句的错误:cannot convert 'Normal*' to 'Normal Sphere::*' in return
进一步澄清:我不是在问指针是如何工作的。(这不是主要问题。)我想知道关于c++中指针的语法。因此,对于我上面指定的函数,我已经收集到我应该指定一个返回指针,因为c++没有空对象。明白了。但是,问题就变成了:函数原型应该是什么样子?在cpp文件中,我有Bala建议的内容(这是我最初的内容,但由于以下错误而更改了它):
Normal* Sphere::hit(Ray ray) {
//stuff is done here
if(something happens) {
return NULL;
}
//other stuff
return new Normal(something, somethingElse);
}
在头文件中,我有Normal *hit(Ray ray)
,但我仍然得到这个消息:prototype for 'Normal* Sphere::hit(Ray)' does not match any in class 'Sphere'
在这一点上,我不清楚为什么找不到那个函数原型。下面是头文件:
class Sphere
{
public:
Sphere();
Vector3 center;
float radius;
Normal* hit(Ray ray);
};
有谁知道为什么它抱怨Sphere
类中没有hit
的匹配原型吗?(我可能会把这个移到一个单独的问题…)
我想你需要一些像
Normal* Sphere::hit(Ray ray) {
//stuff is done here
if(something happens) {
return NULL;
}
//other stuff
return new Normal(something, somethingElse);
}
有几种相当标准的方法可以做到这一点。对于不同的方法有不同的权衡,我不打算在这里展开。
方法1:失败时抛出异常。
Normal Sphere::hit(Ray ray)
{
//stuff is done here
if(something happens) {
throw InvalidIntersection;
}
//other stuff
return Normal(something, somethingElse);
}
void example(Ray r)
{
try {
Normal n = s.hit(r);
... SUCCESS CASE ...
}
catch( InvalidIntersection& )
{
... FAILURE CASE ...
}
}
方法2返回指向新分配对象的指针。(您也可以使用智能指针,或auto_ptrs使其更简洁)。
Normal* Sphere::hit(Ray ray)
{
//stuff is done here
if(something happens) {
return NULL
}
//other stuff
return new Normal(something, somethingElse);
}
void example(Ray ray)
{
Normal * n = s.hit(ray);
if(!n) {
... FAILURE CASE ...
} else {
... SUCCESS CASE ...
delete n;
}
}
方法3是更新一个现有的对象。(您可以传递引用,但我使用的惯例是任何输出参数都是通过指针传递的)。
bool Sphere::hit(Ray ray, Normal* n)
{
//stuff is done here
if(something happens) {
return false
}
//other stuff
if(n) *n = Normal(something, somethingElse);
return true;
}
void example(Ray ray)
{
Normal n;
if( s.hit(ray, &n) ) {
... SUCCESS CASE ...
} else {
... FAILURE CASE ...
}
}
方法4:返回一个optional<Normal>
(使用boost或类似)
optional<Normal> Sphere::hit(Ray ray)
{
//stuff is done here
if(something happens) {
return optional<Normal>();
}
//other stuff
return optional<Normal>(Normal(something, somethingElse));
}
void example(Ray ray)
{
optional<Normal> n = s.hit(ray);
if( n ) {
... SUCCESS CASE (use *n)...
} else {
... FAILURE CASE ...
}
}
如果您使用Boost库,那么您可以使用Boost::optional。这就得到了一个非常接近于空值的值:
boost::optional<Normal> Sphere::hit(Ray ray) {
//stuff is done here
if(something happens) {
return boost::none;
}
//other stuff
return Normal(something, somethingElse);
}
boost:: optional<;T>是一个包装器类,它包含T的一个实例或boost::none (boost::none_t的一个实例)。
参见http://www.boost.org/doc/libs/1_47_0/libs/optional/doc/html/index.html了解更多详细信息。
在c++中没有"null对象"这种东西。不过也有空指针。您可以实现您设计的一个特殊对象,您在逻辑上将其视为"null",但它不是c++语言的一部分。
NULL返回值只在返回Normal对象的指针时有效,NULL表示空指针,而不是空对象。
在这种情况下,我要做的是为这个对象定义一个'null'或无效状态。由于您正在处理表面法线,您可以将长度== 0的法线视为无效状态,因此您可以这样做:
Normal Sphere::hit(Ray ray) {
//stuff is done here
if(something happens) {
return Normal();
}
//other stuff
return Normal(something, somethingElse);
}
那么你的普通类应该是这样的:
class Normal {
public:
Normal() : x(0), y(0), z(0), len(0) {}
// ... other constructors here ...
bool isValid() const { return (len != 0) };
// ... other methods here ...
private:
float x, y, z, len;
};
但是,我的代码有些不同,因为星号不能解决我的问题,这是:
从你的问题看来,你期望在类名之后简单地添加*
将解决你的问题。然而,这种期望来自于缺乏对指针是什么、何时使用指针以及类型系统的重要性的理解。因此,这个答案的其余部分有望澄清这些观点。
首先,c++是一种强类型语言。这意味着当将一个变量分配给另一个变量时,两个变量必须具有相同的类型。例如,假设下面的代码A和B是没有定义成员的基本类:
A a;
B b;
a = b; //compiler error here due to type mismatch
这是因为a
和b
是不同的类型。
现在假设您使用*
创建了一个指针。这也是一个不同类型的变量:
A a;
A* p_a;
a = p_a; //compiler error due to type mismatch
p_a
和a
不是同一类型的变量。
现在错误:
生成请求将' int '类型转换为' Normal '非标量类型
是因为表达式:
return NULL
的类型是int
(你会发现,如果你查找它的#定义为0),但你的函数的返回类型是Normal
。
要解决这个问题,您必须将函数返回类型更改为pointer to a Normal
对象。
Normal* Sphere::hit(Ray ray)
并返回一个pointer to a Normal
对象:
return new Normal(something, somethingElse);
然而,在这个阶段,尽管编译器错误应该得到解决,但您现在需要关注管理动态分配的内存。我不能在这篇文章中讨论这个问题,所以我就这样吧。
更新:
这是回答你问题的第二部分。头文件中的类声明应该以;
结束
您不应该返回NULL
,这是int
类型的零常量,而是返回由无参数构造函数构造的Normal
类的空实例,通常。
返回Normal();
一般来说,最好另外定义isEmpty()
方法。
这样你就可以像这样检查Null
实例:
if(obj_of_class_Normal.isEmpty())
//do something.
我曾经面对过这类问题。如果需要,对于非限定条件,可以只返回具有所需最低/默认值的normal
对象,例如:
Normal Sphere::hit(Ray ray) {
//stuff is done here
if(something happens) {
return Normal(0,0); //here I take the example by constructing the 'normal' object with all value zeros
}
//other stuff
return Normal(something, somethingElse);
}
因为你的函数的返回类型是Normal
,你可以只传递一个类型为Normal
的最低值的对象,如例子0或其他,然后你可以进一步处理当函数的堆栈终止。
- 如何在映射中返回null
- 为什么返回 NULL 不会破坏函数?
- fopen 在 gdb 中返回 NULL
- 为什么要从main()返回NULL?
- 为什么TinyXML2的XMLDocument::FirstChild()函数在尝试解析这个有效的XML文件时返回NULL?
- Box2D World.GetBodyList() 返回 NULL,但 World 显然正在更新对象
- boost::p ython:PyErr_Fetch始终返回 NULL 回溯
- 如何在 Visual C++ 中从返回类型为 map 的函数返回 null?
- 如何在C++中返回Null作为引用
- 从模板化函数返回Null对象
- GDALOpen 在 GEOTiff 文件上返回 null
- PyThreadState_GET() 从 PyImport_GetModuleDict() 中返回 NULL
- (位图)LoadImage() 返回 NULL,GetLastError() 返回 0
- 在构造函数处将类对象强制转换为接口始终返回 NULL
- 如何为迭代器返回"null"值?
- 具有 4 个指针的节点的递归插入函数返回 null
- winAPI FindResource 仅在 DLL 中返回 NULL
- 使用 dlopen/dlsym 打开C++共享库 - dlsym 返回 NULL
- SetWindowsHookEx 在挂接到其他线程时返回 NULL
- 尚未归shared_ptr所有的实例的 shared_from_this() 总是返回 null?