类 和 C++ 封装 (OOP)

Classes and encapsulation in C++ (OOP)

我们现在在我的课程中使用 OOP 在 CPP 中做 classes,我对它们有点迷茫。我了解整个过程 - 我想,但我似乎无法做到正确。我对此很陌生,所以请放轻松。

基本上,此分配任务的整个前提是创建以下变量和 classes:

  1. 创建一个 class 命名的三角形
  2. 封装 a、b、c - 三角形的边长
  3. bool Set (双 aa, 双 bb, 双 cc); - 设置值和 returns true 或 false 取决于基于这些长度的三角形是否可能
  4. double Perim(); - 计算三角形的周长。
  5. 双倍面积(); - 计算三角形面积。
  6. bool isRect(); - 检查这是否是直角三角形。

我希望这是有道理的?

这是我目前的情况:

main.cpp 文件(远未完成,这只是目前的占位符):

#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.";
        }
}

当然这还远未完成,但我正在努力 link 将所有内容整合在一起。 我试图获取 Main.cpp 文件,当此人输入值时,应该将其传递给其他 cpp 文件并进行计算,一旦完成,return 通过对象将值传递给 Main cpp (尚未创建)。 如果这有意义?

几个小时以来,我一直在努力思考这个问题,但我似乎无法做到正确,希望这里有人能指出我正确的方向吗?

在此先感谢您,对于乱七八糟的代码深表歉意..

这是一个可以接受的开始。但是这里有几个问题。

让我们先看一下header:

您需要删除 cpp 文件的 #include。您应该只在 header 中包含 header。并且最好将自己限制在 header 中的代码真正需要的 header 中。例如,class 定义并不真正需要 <iostream>。因此,将此包含移动到需要它的 cpp 中。

你还需要删除 using 子句:这应该在 cpp 中使用,而不是在 headers 中,因为它会导致包含 header 的文件忽略导入了另一个名称空间,这可能会在以后产生冲突(在较大的项目中)。关于如何使用 headers here.

的更多建议

那么 Triangle 是 class 而不是函数。所以你必须用 class Triangle { ... }; 而不是 class Triangle() {...};

来定义它

我还希望以下成员函数是 public:

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.  
  }

然后你可以 return 一个布尔表达式。无需更明确:

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

最后,您的 set 函数需要修改:您必须 return truefalse。你最好不要在 return 语句中使用 cout,而是在 returning 之前。最后但并非最不重要的是,您必须在分配成员变量之前执行有效性测试。

终于到了 main()

输入流和输出流是不同的东西。所以不要在 cin !

上尝试 <<endl

输入成功后,可以t.set(...)使用用户输入的值来改变t。

如果t.set(...) return为真,您可以显示函数的结果。例如:

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

如果结果为假,那么最好告诉用户你不能再用这样的三角形做任何事情了。

我想你知道如何编译 main.cpp 和 triangle.cpp 一起编译。

1) 包括 header 个文件,而不是 cpp 文件!

删除:

    #include "Triangle.cpp"

原因:

cpp 文件是被编译的。它们依赖于 header 个文件,而不是相反。 headers 可以依赖于其他 headers,这实际上经常发生。但他们不应该依赖于 cpp 文件。

2) 将 headers 包装在 ifndef/define 块中。

移动:

#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> 视为 copy-pasting 覆盖该行的 iostream 文件的内容。 因此,当您在 main.cpp 和 triangle.cpp 中 #include "triangle.h" 时,您是在描述三角形 class 的外观 到每个 cpp 文件。 main.cpp 需要知道才能创建和使用三角形,triangle.cpp 需要知道才能创建和使用三角形 正确实现Triangle中的功能。

如果包含一个文件两次,则该文件实际上是 copy-pasted 两次。通常是 re-defining 它的内容, 将是一个编译错误。 ifndef/define 块所做的是说“嘿,如果 TRIANGLE_H 尚未定义,这是第一个 它被包含的时间。因此,继续定义 TRIANGLE_H 以及所有文件内容。下次包含triangle.h 我们会看到 TRIANGLE_H 已经定义了,我们直接跳过 header 的内容,而不是 re-defining 三角是.

我建议你把它移到顶部的原因是你包括了 iostream,triangle.cpp(我们已经讨论过那部分)和 每次包含 triangle.h 时都使用命名空间标准。没必要。

3) 修复三角形class声明

变化:

    class Triangle(){

    class Triangle {

原因:

你很接近!但是您将声明构造函数的语法与声明 class.

的语法混淆了

4) 创建您打算在 Triangle 之外使用的函数 public.

移动:

上面的 "public:" 访问说明符 double Perim();

原因:

如果您想从 main.cpp(或从除三角形 class 内部以外的任何地方调用方法:Perim、Area 和 IsRect!) 你需要这些方法是 public.

您可能很想制作所有内容 public,但这是一种糟糕的形式 - 您的导师特别说过 "encapsulate a, b, c"。 你可以 google 封装设计模式来理解为什么。这里就不展开了。

5) 填写你的三角形构造函数

查看方法:

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

变化:

  • 在 header 文件中,您没有给出三个参数的名称。这不是错误,但很奇怪。 您可能应该给这些参数命名。

  • 在您的另一个构造函数(没有参数的构造函数)中,您表明您知道如何为 a、b 和 c 赋值! 继续在这个方法中给它们赋值。

  • 考虑一下你是否真的想使用int作为参数的类型。 您将边长存储为双精度,但将它们作为整数提供给构造函数。这不是错误,但很奇怪。

6) 修复Set方法的body

查看方法:

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

注:

记住方法就是交换。你给它提供它的参数,它做一些工作并且它 return 给你一些值(除非它 'returns' 无效)。 您的方法要求 3 个双打,并且 returning 一个布尔值。如果您 return 是一个布尔值,则表示您同意返回真值或假值。 在这里你试图 return 任何 cout << "..."; return秒。这听起来不像你想要的(即使它编译)。你不关心 cout return 是什么,对吧?

变化:

不要从这个函数中计算出任何东西。如果三角形可能,则 return 为 true,如果不可能,则为 false。 你可以从调用 Set 的地方计算出任何你想要的东西。

7) 封装a、b、c。

您已将 b 和 c 设为私有。这是封装的一半。 你的导师可能要你为三角形中的这些变量写一个getter和setter。

示例:

    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 的调用以获取用户输入后,执行以下操作:

  • 创建一个布尔变量来存储集合的结果,我们稍后会用到它
  • 调用 t 上的 Set 函数,提供用户输入的 3 个长度。将 Set 的 return 存储在我们的布尔值中。
  • 写一个if语句。检查该布尔值是否为真。如果是,打印"A triangle with these parameters is possible.",否则打印"A triangle with these parameters is NOT possible."
  • 如果您的任务要求您做任何其他事情或任何不同的事情,例如打印 Perim、Area 和 isRect 的结果,那就去做吧!