我知道这可能与以下内容重复: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 temporary
和conversion 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 ++没有null对象。得到它了。但是,问题就变成了:函数原型应该是什么样的?在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);
};
任何人都可以看到它为什么抱怨hit
类中Sphere
没有匹配的原型? (我可能会将此问题转移到另一个问题......)
答案 0 :(得分:19)
有几种相当标准的方法可以做到这一点。这些方法有不同的权衡,我不打算在这里讨论。
方法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>
(使用提升或类似)
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 ...
}
}
答案 1 :(得分:8)
如果使用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);
}
升压::任选的LT; T&GT;是一个包装类,包含一个T实例或boost :: none(一个boost :: none_t实例)。
有关详细信息,请参阅http://www.boost.org/doc/libs/1_47_0/libs/optional/doc/html/index.html。
答案 2 :(得分:7)
我认为你需要像
这样的东西Normal* Sphere::hit(Ray ray) {
//stuff is done here
if(something happens) {
return NULL;
}
//other stuff
return new Normal(something, somethingElse);
}
能够返回NULL;
答案 3 :(得分:4)
在C ++中,没有“null对象”这样的东西。但是有空指针。您可以实现设计中的一个特殊对象,在逻辑上将其视为“null”,但它不是C ++语言的一部分。
答案 4 :(得分:1)
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;
};
答案 5 :(得分:0)
但是,我的代码有些不同,因为 星号不能解决我的问题,这就是:
从您的问题看,您希望只需在课程名称后添加*
即可解决您的问题。然而,这种期望来自于缺乏对指针是什么,何时使用指针以及类型系统的重要性的理解。所以这个答案的其余部分有望澄清这些要点。
首先,C ++是一种强类型语言。这意味着当将一个变量分配给另一个变量时,2个变量必须属于同一类型。例如,假设在下面的代码中,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
(你会发现如果你查找它的#defined为0),但你的函数的返回类型是Normal
。
要解决此问题,您必须将函数返回类型更改为pointer to a Normal
对象。
Normal* Sphere::hit(Ray ray)
并返回pointer to a Normal
个对象:
return new Normal(something, somethingElse);
然而,在此阶段虽然应该解决编译器错误,但现在您需要管理动态分配的内存。我不能在这篇文章中介绍它,所以我会保留它的样子。
这是为了解决你问题的第二部分。您的标头文件中的类声明应以;
终止。
答案 6 :(得分:0)
您不应该返回NULL
,它是类型int
的零常量,而是通常返回由no arg构造函数构造的类Normal
的空实例。
因此返回Normal();
通常,优良作法是另外定义方法isEmpty()
。
这样,您可以像这样检查Null
实例:
if(obj_of_class_Normal.isEmpty())
//do something.