我刚刚用object-orinted(cpp)编写了我的第一个迷你项目。程序似乎运行良好,但是当我编译它时,我收到以下警告: :警告C4715:'Collection :: getCircleAt':并非所有控制路径都返回值。 我不明白这个警告的原因是什么。
我想补充一些关于我的计划的话: 程序在整数xy平面中输入一组圆,并检查哪个圆包含平面中的给定点。为了那个任务,我使用了课程。 “Point”类通过其坐标表示一个点。 “Circle”类表示平面中的彩色圆。该类包含一个“Point”类型的变量,它表示圆的中心和半径。该类还包含一个名为“color”的变量,(由整数0或2表示,当0表示圆圈不包括给定的点,2表示相反),以及检查是否包含给定点的函数在一定的圈子里。 最后,我们有了“Collection”类,它代表了一个圆圈集合。 变量“count”是圆圈的数量,变量“circles”是指向集合中圆圈的指针数组。 此类包含函数getCircleAt,它返回包含该点的圆。这就是上面显示警告的功能。
Heres是我的代码:
#include <iostream>
using namespace std;
#include "point.h"
#include "circle.h"
#include "collection.h"
int main()
{
Collection g(4, 3, 2, 0);
cout << "-- before setColor(2) --" << endl;
g.print();
Point p(5, 1);
g.getCircleAt(p).setColor(2);
cout << "-- after setColor(2) --" << endl;
g.print();
return 0;
}
#ifndef POINT_H
#define POINT_H
class Point
{
public:
Point(int x, int y);
int getX() const;
int getY() const;
void setX(int x);
void setY(int y);
void print() const;
private:
int x, y;
};
#endif
#ifndef CIRCLE_H
#define CIRCLE_H
#include "point.h"
class Circle
{
public:
Circle(int x, int y, int r, int color);
int getColor() const;
void setColor(int color);
bool contains(const Point &p) const;
void print() const;
private:
const Point center;
int radius, color;
};
#endif
#ifndef COLLECTION_H
#define COLLECTION_H
#include "circle.h"
class Collection
{
public:
Collection(int radius, int width, int height, int color);
~Collection();
Circle& getCircleAt(const Point &p);
void print() const;
private:
int count;
Circle **circles;
};
#endif
#include <iostream>
using namespace std;
#include "point.h"
Point::Point(int x,int y )
{
setX(x);
setY(y);
}
void Point::setX(int x)
{
this->x=x;
}
void Point::setY(int y)
{
this->y=y;
}
int Point::getX() const
{
return x;
}
int Point::getY() const
{
return y;
}
void Point::print() const
{
cout <<"x="<< this->x <<" "<<"y" << this->y ;
cout <<" ";
#include <iostream>
using namespace std;
#include "circle.h"
Circle::Circle(int x=0,int y=0,int r=0,int color=0):center(x, y),radius(r),color(color)
{
}
int Circle::getColor() const
{
return color;
}
void Circle::setColor(int color)
{
this->color=color;
}
bool Circle::contains(const Point &p) const
{
int distX, distY;
distX=p.getX()-center.getX();
distY=p.getY()-center.getY();
if ((distX*distX + distY*distY) > (radius*radius))
return false;
return true;
}
void Circle::print() const
{
cout<<endl<<"the center of the circle is ("<<center.getX()<<" ,"<<center.getY()<<")"<<" radius "<<radius<<" color "<<color<<endl;
}
#include <iostream>
using namespace std;
#include "collection.h"
Collection::Collection(int radius, int width, int height, int color)
{
int i ,j;
count=height*width;
circles=new Circle* [count];
for(i=0;i<height;i++)
for(j=0;j<width;j++)
circles[j+(i*width)]=new Circle (j*2*radius,i*2*radius,radius,color);
}
Collection::~Collection()
{
delete []circles;
}
Circle& Collection::getCircleAt(const Point &p)
{
for(int i=0;i<count;i++)
if(circles[i]->contains(p) )
return *(circles)[i];
}
void Collection::print() const
{
for (int i=0;i<count;i++)
circles[i]->print();
}
预期输出为:
-- before setColor(2) --
Circle center=(0,0) radius=4 color=0
Circle center=(8,0) radius=4 color=0
Circle center=(16,0) radius=4 color=0
Circle center=(0,8) radius=4 color=0
Circle center=(8,8) radius=4 color=0
Circle center=(16,8) radius=4 color=0
-- after setColor(2) --
Circle center=(0,0) radius=4 color=0
Circle center=(8,0) radius=4 color=2
Circle center=(16,0) radius=4 color=0
Circle center=(0,8) radius=4 color=0
Circle center=(8,8) radius=4 color=0
Circle center=(16,8) radius=4 color=0
答案 0 :(得分:2)
在此代码中:
Circle& Collection::getCircleAt(const Point &p)
{
for (int i = 0; i < count; i++)
if (circles[i]->contains(p))
return *(circles)[i];
}
当没有圆圈包含p
时,不执行任何返回语句。这意味着当发生这种情况时,函数的返回值是未定义的。
有几种方法可以解决这个问题。最简单的方法是返回指针而不是引用,并在没有找到圆时返回nullptr
:
Circle* Collection::getCircleAt(const Point &p)
{
for (int i = 0; i < count; i++)
if (circles[i]->contains(p))
return circles[i];
return nullptr;
}
这里建议的另一个解决方案是抛出异常。但是,我不建议这样做,因为例外情况除外。 getCircleAt()
在某个给定位置找不到圆圈没有什么特别之处。这是正常的事情。这不是错误。
更好的解决方案(在我看来)是完全更改API,而是返回圆的索引,而不是圆本身。找不到圆圈时,返回-1:
int Collection::getIndexAt(const Point &p)
{
for (int i = 0; i < count; i++)
if (circles[i]->contains(p))
return i;
return -1;
}
然后添加operator []
重载以通过索引访问圈子:
class Collection
{
public:
// ...
Circle& operator [](size_t index)
{
return *circles[i];
}
};
然后函数的调用者需要检查是否找到了圆圈:
auto index = g.getIndexAt(p);
if (index >= 0) {
g[index].setColor(2);
cout << "-- after setColor(2) --" << endl;
g.print();
} else {
cout << "-- circle not found at position --" << endl;
}
作为旁注,您的Collection
析构函数不正确。你没有释放你分配的圈子。您只能释放动态数组。你需要:
Collection::~Collection()
{
// Free each circle.
for (int i = 0; i < count; ++i)
delete circles[i];
// Free the array.
delete[] circles;
}
代码中的另一个(无关的)问题是,您在构造函数的实现中为Circle::Circle()
构造函数提供默认参数值,而不是在其声明中。你应该改变它。应在声明中指定默认参数。所以这样做:
class Circle {
public:
Circle(int x = 0, int y = 0, int r = 0, int color = 0);
并从实现中删除默认参数值:
Circle::Circle(int x, int y, int r, int color)
此外,除非这是内存分配和指针练习,否则您应切换到std::vector<Circle>
,而不是使用new
和delete
的指针。手动内存管理容易出错。例如,你在上面的Collection
析构函数中弄错了并且泄漏了内存。使用像vector
这样的标准容器将为您处理内存管理。一个好的经验法则是永远不要使用new
和delete
,除非你真的需要。
答案 1 :(得分:1)
Collection::getCircleAt
都不会返回。这是未定义的行为,即使未触发错误,也可能导致一些非常奇怪的行为。具有非void
返回类型的函数必须在每个路径返回离子。这在评论中被打死了。
没有涵盖的是如何修复它。
Circle& Collection::getCircleAt(const Point &p)
{
for(int i=0;i<count;i++)
if(circles[i]->contains(p) )
return *(circles)[i];
throw std::runtime_error("No circle at P")
}
如果p
经常与圈子无关,则会造成严重的性能损失。因为它不是例外的行为。您只想对异常行为使用异常。如果在Circle
处应该有一个p
并且在没有特殊报告的情况下这是一个罕见且不寻常的事件,那么我们就是例外。
g.getCircleAt(p).setColor(2);
如果没有Circle
,将完全失败,这表明这是一个不错的选择。您可以在此处捕获并处理异常,将其留给调用堆栈中的另一个函数来处理(在提问者的示例中没有任何内容)或让程序崩溃并收集捆绑的消息看看原因的例外。有关详细信息,请阅读文本有关异常处理的部分。
如果Circle
处的p
不是常规预期事件,则异常可能是错误的工具。继续选择2
Circle* Collection::getCircleAt(const Point &p)
{
for(int i=0;i<count;i++)
if(circles[i]->contains(p) )
return (circles)[i];
return nullptr;
}
请注意,返回类型已更改为指针,因此返回null是合法的。即使编译器允许,也不要将自己置于返回空引用的位置。空引用是一个令人讨厌的惊喜,没有人应该处理。指针至少会给你一些警告,告诉你可以使用null,所以请注意:
g.getCircleAt(p)->setColor(2);
刚取消引用并访问空指针。 KABOOM。如果程序没有崩溃,并且它没有必要,程序就会疯狂。你需要做更多。例如,
Circle * c = g.getCircleAt(p)
if (c != nullptr)
{
c->setColor(2);
}
else
{
// do error handling
}
你现在程序员必须自己完成所有的错误处理,但你有完全的控制权并且你知道成本。如果它不重要,请保持冷静并继续。如果需要处理,请处理它。
std::optional
optional
使金丝雀价值正式化。您可以测试它以确保您得到响应然后继续。首先,一些文档:http://en.cppreference.com/w/cpp/utility/optional
optional
字面上刚刚出现在C ++ 17标准修订版中。我认为它在9月或10月正式批准,因此除非您使用最新的编译器,否则它可能无法使用。
事实上,我没有这样的编译器,也无法提供我已经测试过的代码,目前可以使用。这就是选项2A的原因。你自己就是这个人。我还没有机会玩它。