Классы и инкапсуляция в C ++ (ООП) - PullRequest
0 голосов
/ 20 февраля 2019

Мы сейчас проводим занятия по CPP на моем курсе, используя ООП, и я немного растерялся с ними.Я понимаю весь процесс - я думаю, но я просто не могу понять это правильно.Я новичок в этом, поэтому, пожалуйста, будьте осторожны со мной.

По сути, вся предпосылка для этой назначенной задачи - создать следующие переменные и классы:

  1. Создать класс с именем Triangle
  2. Инкапсулируйте a, b, c - длины сторон треугольника
  3. Набор bool (double aa, double bb, double cc);- устанавливает значения и возвращает true или false в зависимости от того, возможен ли треугольник, основанный на этих длинах
  4. double Perim ();- рассчитывает периметр треугольника.
  5. double Area ();- вычисляет площадь треугольника.
  6. bool isRect ();- проверяет, является ли это прямоугольным треугольником.

Надеюсь, это имеет смысл?

Вот что у меня есть:

main.cpp file (на данный момент это просто заполнитель:

#include <iostream>
#include "triangle.h"

using namespace std;


int main() {
  Triangle t;
  int aa, bb, cc;

  cout <<"Triangle side 1 - " <<endl;
  cin >> aa <<endl;
  cout <<"Triangle side 2 - ";
  cin >> bb <<endl;
  cout <<"Triangle side 3 - ";
  cin >> cc <<endl;


return 0;
}

файл Triangle.h:

#include <iostream>
#include "Triangle.cpp"

using namespace std;

#ifndef TRIANGLE_H
#define TRIANGLE_H

class Triangle(){

private:
  double a;
  double b;
  double c;

  double Perim();
  double Area();
  bool IsRect();

public:
  Triangle();
  Triangle(int, int, int);
  bool set(double aa, double bb, double cc);
};

#endif

и файл Triangle.cpp (с формулами для расчета всего)

#include "Triangle.h"

  Triangle::Triangle(){
   a = b = c = 0;
   Perim = 0.0;
   Area = 0.0;
 }

 Triangle::Triangle(int aa, int bb, int cc){

 }

  double Triangle::Perim(){
    return a + b + c;
  }

  double Triangle::Area(){
    s = (a+b+c)/2;
    Area = SQRT(s(s-a)(s-b)(s-c));
    return Area;
  }

  bool Triangle::isRect(){
    return (((a*a) + (b*b)) == (c*c)) ? true : false; //---checks if this is a right angle triangle, and should return true or false.
  }

  bool Triangle::Set(double aa, double bb, double cc){
    a = aa;
    b = bb;
    c = cc;

        if (a + b > c && a + c > b && b + c > a){//if one of these criteria is false, then a triangle is not possible.
          return cout << "A triangle with these parameters is possible.";
        }
        else{
          return cout << "A triangle with these parameters is NOT possible.";
        }
}

Конечно, это далеко не завершено, но я изо всех сил пытаюсь связать все вместе.Я пытаюсь получить файл Main.cpp, когда человек вводит значения, которые должны быть переданы в другой файл cpp и произведены вычисления, и как только это будет сделано, чтобы вернуть значения в Main cpp через объекты (которые еще предстоит создать).Если это имеет смысл?

Я пытался обернуть голову вокруг этого уже несколько часов, и я просто не могу понять, как это правильно, надеялся, что кто-то здесь укажет мне правильное направление?

Заранее спасибо, и извините за грязный код ..

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

1) Включить заголовочные файлы, а не файлы cpp!

Удалить:

    #include "Triangle.cpp"

причина:

Файлы cpp - это то, что компилируется.Они зависят от заголовочных файлов, а не наоборот.Заголовки могут зависеть от других заголовков, что часто происходит на самом деле.но они не должны зависеть от файла cpp.

2) Обернуть заголовки в блоки ifndef / define.

Move:

#ifndef TRIANGLE_H и #define TRIANGLE_H в начало файла над всем остальным.Стилистически вы можете прокомментировать, что файл делает над блоком ifndef / define вместо

Пример:

    // This is the triangle header file! Here is where I describe it.
    #ifndef TRIANGLE_H
    #define TRIANGLE_H
    // TODO: Put the includes here
    // TODO: Put your class here
    #endif

Причина:

В C ++ вы можете думать о строке: #include <iostream> как о вставке копии содержимого файла iostream поверх этой строки.Поэтому, когда вы #include "triangle.h" в main.cpp и triangle.cpp, вы описываете, как будет выглядеть класс треугольника для каждого из этих файлов cpp.Файл main.cpp должен знать, чтобы он мог создавать и использовать треугольник, а файл triangle.cpp должен знать, чтобы он мог правильно реализовать функции в треугольнике.

Если вы дважды включите файл, этот файл будет эффективно скопирован-печено дважды.Обычно это будет переопределять его содержимое, что будет ошибкой компиляции.Блок ifndef / define говорит: «эй, если TRIANGLE_H еще не определен, это первый раз, когда он был включен. Поэтому давайте определим TRIANGLE_H вместе со всем содержимым файла. В следующий раз triangle.h будетвключаем, мы увидим, что TRIANGLE_H уже определен, и мы пропустим прямо содержимое этого заголовка, вместо того, чтобы переопределять, что такое Trinagle.

Причина, по которой я предлагаю вам переместить его наверх, это вывключаем iostream, triangle.cpp (мы уже говорили об этой части) и используем пространство имен std каждый раз, когда включается triangle.h. В этом нет необходимости.

3) Исправьте объявление класса треугольника

Изменение:

    class Triangle(){

на

    class Triangle {

Причина:

Вы близки! Новы путаете синтаксис объявления конструктора с синтаксисом объявления класса.

4) Делайте функции, которые вы намереваетесь использовать, вне Triangle общедоступными.

Move:

доступ "public:"указатель выше double Perim();

Причина:

Если вы хотите вызвать методы: Perim, Area и IsRect из main.cpp (или из anywehre, но внутрикласс треугольника!) вам нужно, чтобы эти методы были общедоступными.

У вас может возникнуть соблазн обнародовать все, но это дурной тон - и ваш инструктор специально сказал «инкапсулировать a, b, c».Вы можете погуглить шаблон проектирования инкапсуляции, чтобы понять, почему.Я не буду вдаваться в подробности.

5) Заполните ваш конструктор треугольника

См. Метод:

    Triangle::Triangle(int aa, int bb, int cc)

Изменения:

  • В заголовочном файле вы не дадите названия трех параметров.Это не ошибка, но это странно.Вам, вероятно, следует дать имена этим параметрам.

  • В другом конструкторе (без параметров) вы показываете, что знаете, как назначать значения a, b и ca!Идите вперед и присвойте им значения в этом методе.

  • Подумайте, действительно ли вы хотите использовать int в качестве типов параметров.Вы сохраняете длины сторон как двойные, но вы предоставляете их конструктору как целые.Это не ошибка, но это странно.

6) Исправить тело метода Set.

См. Метод:

    Triangle::Set(double aa, double bb, double cc)

Примечание:

Помните, что метод обмена.Вы предоставляете ему его параметры, он выполняет некоторую работу и возвращает вам некоторое значение (если только он не «возвращает» void).Ваш метод запрашивает 3 двойных и возвращает бул.Если вы возвращаете логическое значение, вы соглашаетесь вернуть истинное или ложное значение.Здесь вы пытаетесь вернуть любой cout << "...";возвращается.Это не похоже на то, что вы хотите (даже если это компилируется).Вас не волнует, что возвращает cout, верно? </p>

Изменения:

Не обращайте внимания на эту функцию.Просто верните true, если треугольник возможен, и false, если это невозможно.Вы можете находить все, что хотите, откуда Сета вызывается.

7) Инкапсулируйте a, b, c.

Вы сделали ab и c приватными.Это половина инкапсуляции.Ваш инструктор вероятно хочет, чтобы вы написали метод получения и установки для этих переменных в треугольнике.

Пример:

    double Triangle::GetA() {
        return a;
    }

    void Triangle::SetA(double aa) {
        a = aa;
    }

Я уйдуэто как пример для выполнения всего остального.

8) Использование вашего треугольника в main.cpp

Если вы берете локальную переменную t, вы можете вызывать функции для нее следующим образом:

    t.SetA(1.1);
    cout << t.GetA() << endl; // will print 1.1

    double theValueOfA; // local variable
    theValueOfA = t.GetA(); // store the result of GetA in our new variable

    cout << theValueOfA << endl; // will also print 1.1

Получив эту информацию, после того, как вы закончите ваши звонки в cin для получения пользовательских вводов, сделайте следующее:

  • создайте логическую переменную для хранения результата наборамы будем использовать это позже.
  • вызовите функцию Set для t, предоставив 3 длины, введенные пользователем.Сохраните возврат Set в нашем логическом значении.
  • Напишите утверждение if.Проверьте, является ли значение этого логического значения истинным.Если это так, выведите «Треугольник с этими параметрами возможен». В противном случае выведите «Треугольник с этими параметрами НЕЛЬЗЯ.» *
  • Если ваше назначение требует, чтобы вы делали что-то еще или что-то иное, например,распечатав результат Perim, Area и isRect, сделайте это!
0 голосов
/ 20 февраля 2019

Это приемлемое начало.Но здесь есть пара вопросов.

Давайте сначала пройдемся по заголовку:

Вам нужно избавиться от #include файла cpp.Вы должны включать только заголовки в заголовок.И лучше ограничьте себя заголовками, действительно требуемыми кодом в заголовке.Например, <iostream> на самом деле не требуется для определения класса.Так что переместите это include в cpp, где это необходимо.

Вам также необходимо избавиться от предложения using: это следует использовать в cpp, а не в заголовках, потому что это приводит к тому, что файл, содержащий заголовок, игнорирует импорт другого пространства имен, что может позжена создание конфликтов (в более крупных проектах).Дополнительные советы по использованию заголовков здесь .

Тогда Triangle является классом, а не функцией.Таким образом, вы должны определить это с помощью class Triangle { ... };, а не class Triangle() {...};

Я также ожидал бы, что следующие функции-члены будут общедоступными:

double Perim();    // These are definitively of interest for users of Triangles
double Area();
bool IsRect(); 

Теперь к реализации

Во-первых, вам нужно избежать путаницы между переменными-членами и функциями-членами:

  Triangle::Triangle(){
   a = b = c = 0;
   // Perim = 0.0;   // NO !! Perim() is a function, you cannot assign a value to it
   // Area = 0.0;
 }

Затем вам нужно объявить переменные, которые вы используете:

 double Triangle::Area(){
    auto s = (a+b+c)/2;                // because s deosn't exist
    return std::sqrt(s*(s-a)*(s-b)*(s-c));   // sqrt requires include <cmaths>
                                       // multiplication must be explicit.  
  }

Тогда вы можете простовернуть логическое выражение.Не нужно быть более явным:

bool Triangle::isRect(){
    return ((a*a) + (b*b)) == (c*c); 
  }

Наконец, ваша функция set нуждается в некоторой переработке: вы должны вернуть true или false.Лучше не использовать cout в операторе возврата, но перед возвратом.И последнее, но не менее важное: перед назначением переменных-членов вы должны выполнить тест на достоверность.

Наконец, к main ()

Входной и выходной поток - разные вещи.Так что не пытайтесь <<endl на cin!

Как только ввод сработает, вы можете использовать t.set(...), чтобы использовать значения, введенные пользователем, для изменения t.

Если t.set(...) вернет true, вы можете отобразить результат выполнения функций.Например:

 cout << "Area: " << t.Area()<<endl; 

Если результат ложный, лучше сообщить пользователю, что вы не можете больше ничего делать с таким треугольником.

Я полагаю, что вы знаете, дляКомпиляция, как скомпилировать main.cpp и triangle.cpp вместе.

...