Минимальное исправление
Как уже указывали другие, одна из основных проблем заключается в том, что вы выделяете встроенный массив из 13 кругов и пытаетесь получить доступ к позиции 13, которая находится прямо за пределами выделенной вами памяти.
Из вашего кода я понимаю, что вашей целью было прочитать ваш файл, который на самом деле состоит из 12 элементов, поэтому все последующие циклы пытаются слишком много читать один круг и слишком много использовать один круг. Вероятно, было бы лучше использовать отдельную переменную для вашего «ссылочного» круга.
Более того, вы используете «while not eof()
» l oop, что обычно (всегда) неверно, но в в этом случае нет смысла, так как вы уже знаете и решили, что файл будет содержать 12 элементов. Таким образом, минимальное исправление для вашего основного может быть следующим:
int main() {
int x, y, radius;
const int SIZE = 12;
Circle myCircleArry[SIZE + 1];
myCircleArry[SIZE] = Circle(5, 9, 3);
cout << endl;
myCircleArry[SIZE].printCircleInfo(); cout << " : ";
ifstream Lab6DataFileHandle;
Lab6DataFileHandle.open("Lab6Data.txt");
for (int i = 0; i < SIZE; i++) {
Lab6DataFileHandle >> x;
Lab6DataFileHandle >> y;
Lab6DataFileHandle >> radius;
myCircleArry[i] = Circle(x, y, radius);
}
for (int i = 0; i < SIZE; i++) {
if (myCircleArry[SIZE].doIBumpIntoAnotherCircle(myCircleArry[i])) {
myCircleArry[i].printCircleInfo();
if (myCircleArry[SIZE] == myCircleArry[i])
{
cout << "*";
}
cout << " ; ";
}
}
Lab6DataFileHandle.close();
myCircleArry[SIZE].printCircleInfo();
}
Обратите внимание, что мы знаем , что SIZE
элементов находятся в файле, мы выделяем SIZE+1
слотов и используем один в поместите РАЗМЕР в качестве эталонного. Циклы go от 0 до SIZE (исключено).
Основная реструктуризация
Вероятно, это должно быть go до Code Review , но поскольку мы здесь ...
Старый включает
Эти
#include <cstdlib>
#include <math.h>
могут стать
#include <cmath>
Вам не нужна старая C стандартная библиотека.
Избегайте using namespace std;
Множество ответов здесь объясните почему.
Мое мнение о вашем Point
Это больше мое мнение, чем актуальные проблемы. Ваш класс
class Point {
protected:
int x, y;
double operator-(const Point &def) {
return sqrt(pow((x - def.x), 2.0) +
pow((y - def.y), 2.0));
}
};
использует защищенные атрибуты, что выглядит бесполезным излишним дизайном. Более того, он отключает возможность инициализации с помощью фигурных скобок.
operator-
между точками не должно указывать расстояние. Это действительно противоречит интуиции с математикой, которую все изучают в школе.
Позже вы сравните центры кругов, поэтому operator==
будет полезно.
Наконец, почему бы не использовать double
координаты?
Результат:
struct Point {
double x, y;
friend double distance(const Point &a, const Point &b) {
return sqrt(pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0));
}
bool operator==(const Point &rhs) const {
return x == rhs.x && y == rhs.y;
}
};
Мой взгляд на ваш Circle
Это ваш Circle
:
class Circle : public Point {
Честно говоря, круг не Точка, поэтому я не думаю, что hineritance - правильный выбор.
private:
int radius;
Это действительно личное: я бы избегал защиты атрибута radius
, позволяя пользователям получить к нему доступ.
public:
Circle() {
this->x = x;
this->y = y;
this->radius = radius;
}
Это совершенно неверно. Он сообщает компилятору, что инициализация по умолчанию должна принимать атрибуты класса (неинициализированные) и использовать их для инициализации тех же вещей, потому что здесь this->x
совпадает с x
(то же самое относится к y
и radius
) . Отбросьте эту бесполезную вещь.
Circle(int x, int y, int radius) {
this->x = x;
this->y = y;
this->radius = radius;
}
Это имеет смысл, но мой личный выбор - следовать стилю Google и обозначать атрибуты объекта с подчеркиванием после имени. Другие предпочитают m_
перед именем. Это позволяет мне избежать беспорядка this->
и случайного использования этих элементов.
void printCircleInfo() {
cout << x << " " << y << " " << radius << " ";
}
Это нормально, но go я бы выбрал более стандартную пару вставок / экстракторов.
bool operator==(const Circle &def) {
return (x == def.x) & (y == def.y) & (radius == def.radius);
}
Неправильное использование &
. Вы обязательно хотите &&
.
bool doIBumpIntoAnotherCircle(Circle anotherCircle) {
if (anotherCircle.radius + radius >= *this - anotherCircle)
return true;
return false;
}
};
Грозное имя (опять же: личное мнение). Методы должны сообщать об объекте, к которому они применяются.
anotherCircle
копируется без причины.
Classi c if (something) return true; else return false;
который легко заменяется на return something;
.
Итак, я бы go с:
struct Circle {
Point center_;
double radius_;
friend std::ostream& operator<<(std::ostream& os, const Circle& c) {
return os << c.center_.x << " " << c.center_.y << " " << c.radius_;
}
friend std::istream& operator>>(std::istream& is, Circle& c) {
return is >> c.center_.x >> c.center_.y >> c.radius_;
}
bool operator==(const Circle &rhs) {
return center_ == rhs.center_ && radius_ == rhs.radius_;
}
bool touches(const Circle& other) {
return radius_ + other.radius_ >= distance(center_, other.center_);
}
};
Теперь функция main
Давайте сделаем программу способной читать произвольное количество кругов и сравнивать их с ваша ссылка. Прекратите использовать встроенные массивы и перейдите к std::vector<>
.
int main()
{
Circle ref = { 5, 9, 3 };
std::cout << ref << " : ";
std::vector<Circle> circles;
std::ifstream is("Lab6Data.txt");
Circle cur;
while (is >> cur) {
circles.push_back(cur);
}
for (const auto& c : circles) {
if (ref.touches(c)) {
std::cout << c;
if (ref == c) {
std::cout << " *";
}
std::cout << " ; ";
}
}
}
Обратите внимание, что мы можем инициализировать Circle с помощью фигурных скобок. Вы также можете отбросить =
и go для унифицированной инициализации.
Открытие потока - это просто вызов конструктора. Закрытие будет автоматически выполнено при уничтожении объекта.
l oop теперь использует экстрактор для чтения Circle
. Честно говоря, это компактно, но версия, которую я считаю наиболее дидактической c, такова:
while (true) {
// Read
Circle cur;
is >> cur;
// Check
if (!is) {
break;
}
// Use
circles.push_back(cur);
}
Обратите внимание на шаблон: infinite l oop с Read / Check / Используйте. Проверьте, где мы можем выйти из l oop. Сначала вы читаете, затем проверяете, была ли операция чтения успешной или неудачной, после чего вы можете использовать данные или выйти на основе этого. Поверьте: напишите свои циклы так, а затем, если действительно необходимо, измените их на другие формы.
Хорошо, мы читаем все круги в файле. Теперь для всех кругов (обратите внимание на использование диапазона для l oop с const auto reference
), если ссылка касается текущего круга, мы печатаем его (с *
, если он равен ссылке) *. 1130 *
Надеюсь, этот длинный коротышка найдет применение ...
Полный код для упрощения копирования и вставки
#include <fstream>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <vector>
struct Point {
double x, y;
friend double distance(const Point &a, const Point &b) {
return sqrt(pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0));
}
bool operator==(const Point &rhs) const {
return x == rhs.x && y == rhs.y;
}
};
struct Circle {
Point center_;
double radius_;
friend std::ostream& operator<<(std::ostream& os, const Circle& c) {
return os << c.center_.x << " " << c.center_.y << " " << c.radius_;
}
friend std::istream& operator>>(std::istream& is, Circle& c) {
return is >> c.center_.x >> c.center_.y >> c.radius_;
}
bool operator==(const Circle &rhs) const {
return center_ == rhs.center_ && radius_ == rhs.radius_;
}
bool touches(const Circle& other) const {
return radius_ + other.radius_ >= distance(center_, other.center_);
}
};
int main()
{
Circle ref = { 5, 9, 3 };
std::cout << ref << " : ";
std::vector<Circle> circles;
std::ifstream is("Lab6Data.txt");
Circle cur;
while (is >> cur) {
circles.push_back(cur);
}
for (const auto& c : circles) {
if (ref.touches(c)) {
std::cout << c;
if (ref == c) {
std::cout << " *";
}
std::cout << " ; ";
}
}
}