如何在C++中返回NULL对象

ego6inou  于 2023-07-01  发布在  其他
关注(0)|答案(8)|浏览(210)

我知道这可能是以下内容的重复:Return a "NULL" object if search result not found
但是,我的代码有一些不同的地方,因为星号并没有解决我的问题,这是:

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 temporaryconversion from ‘Normal*’ to non-scalar type 'Normal' requested
我知道为什么我得到这个警告,但我不知道如何解决它。如何在函数结束后的最后一行返回一个Normal对象,以及如何在第一次返回一个NULL对象?(如果有一个术语来描述这些类型的回报,请让我知道,这样我也可以更多地阅读它。
为了澄清一个评论者的问题,我尝试了这些事情:
我试着这样做:cpp文件中的Normal *Sphere::hit(Ray ray)和头文件中的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);,我在第二个return语句中得到了这个错误:cannot convert 'Normal*' to 'Normal Sphere::*' in return

**进一步澄清:**我不是在问指针如何工作。(这不是主要的问题。)我想知道C中关于指针的语法。因此,给定我上面指定的函数,我发现我应该指定一个返回指针,因为C没有空对象。明白了。但是,问题就变成了:函数原型应该是什么样的?在cpp文件中,我有巴拉的建议(这是我最初的建议,但由于以下错误而更改了它):

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的匹配原型吗?(我可能会把这个问题转移到另一个问题上……)

igsr9ssn

igsr9ssn1#

我觉得你需要像

Normal* Sphere::hit(Ray ray) {
   //stuff is done here
   if(something happens) {
       return NULL;
   }
   //other stuff
   return new Normal(something, somethingElse);
}

可以返回NULL;

hsgswve4

hsgswve42#

有几种相当标准的方法可以做到这一点。这些方法有不同的权衡,我不打算在这里讨论。
方法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 ...
  }
}
bq8i3lrv

bq8i3lrv3#

如果使用Boost库,则可以使用boost::optional。这给了你一个非常接近null的值:

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>是一个 Package 类,它包含T的示例或boost::none(boost::none_t的示例)。
请参阅http://www.boost.org/doc/libs/1_47_0/libs/optional/doc/html/index.html了解更多详细信息。

avwztpqn

avwztpqn4#

在C中,没有“空对象”这样的东西。但是有null指针。你可以实现一个特殊的对象,你的设计,你逻辑上视为“空”,但它不是 C 的一部分。

pkwftd7m

pkwftd7m5#

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;
};
f5emj3cl

f5emj3cl6#

但是,我的代码有一些不同的地方,因为星号并没有解决我的问题,这是:
从您的问题来看,您似乎希望在类名后添加一个*就可以解决您的问题。然而,这种期望来自于缺乏对指针是什么、何时使用指针以及类型系统的重要性的理解。因此,本答案的其余部分有望澄清这些观点。
首先,C++是一种强类型语言。这意味着当将一个变量赋值给另一个变量时,这两个变量必须是相同的类型。例如,假设在下面的代码中,A和B是没有定义成员的基本类:

A a;
B b;
a = b; //compiler error here due to type mismatch

这是因为ab是不同的类型。
现在假设您使用*创建了一个指针。这也是一个不同类型的变量:

A a;
A* p_a;
a = p_a; //compiler error due to type mismatch

p_aa不是同一类型的变量。
现在错误:
请求从“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);

然而,在这个阶段,虽然编译器错误应该被解决,但是您现在需要考虑管理动态分配的内存。我不能在这篇文章中涵盖这一点,所以我会让它保持原样。

更新:

这是回答你问题的第二部分。头文件中的类声明应以;结尾。

jvlzgdj9

jvlzgdj97#

你不应该返回NULL,这是一个int类型的零常量,而是返回一个由no arg构造函数构造的类Normal的空示例。
因此返回Normal();
通常,最好另外定义方法isEmpty()
这样你就可以像这样检查一个Null示例:

if(obj_of_class_Normal.isEmpty())
       //do something.
nhn9ugyo

nhn9ugyo8#

我曾经面对过这种问题。如果你想,对于非限定条件,你可以只返回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或其他值,然后你可以在函数的堆栈终止时进一步处理。
希望这能解决你的问题。

相关问题