简体   繁体   English

C ++(OOP)中的类和封装

[英]Classes and encapsulation in C++ (OOP)

We're doing classes in CPP at my course right now using OOP and Im a bit lost with them. 我们正在使用OOP在我的课程中进行CPP课程,而且我有点迷失了他们。 I understand the whole process - I think, but I just cant seem to get it right. 我理解整个过程 - 我想,但我似乎无法做到正确。 Im quite new at this so please go easy on me. 我是新手,所以请放轻松我。

Basically, the whole premise for this assigned task is to create the following variables and classes: 基本上,这个分配任务的整个前提是创建以下变量和类:

  1. Create a class named Triangle 创建一个名为Triangle的类
  2. Encapsulate a, b, c - the triangle side lengths 封装a,b,c - 三角形边长
  3. bool Set (double aa, double bb, double cc); bool Set(双aa,双bb,双cc); - sets the values and returns true or false depending on whether a triangle based on those lengths is possible - 设置值并返回true或false,具体取决于是否可以使用基于这些长度的三角形
  4. double Perim(); 双Perim(); - calculates the perimeter of the triangle. - 计算三角形的周长。
  5. double Area (); 双面积(); - calculates the triangle area. - 计算三角形区域。
  6. bool isRect(); bool isRect(); - checks whether this is a right-angle triangle. - 检查这是否是一个直角三角形。

I hope that makes sense? 我希望这是有道理的?

Heres what I have so far: 以下是我到目前为止的情况:

main.cpp file (far from complete, this is just as a placeholder at the moment): 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 file: 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

and Triangle.cpp file (with the formulas to calculate everything) 和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.";
        }
}

Of course this is far from complete, but Im struggling to link everything together. 当然,这远非完整,但我努力将所有事物联系在一起。 Im trying to get the Main.cpp file, when the person enters the values, that should be passed to other cpp file and calculations made, and once thats done, to return the values to Main cpp through objects (yet to be created). 我试图获取Main.cpp文件,当人输入值时,应该传递给其他cpp文件并进行计算,并且一旦完成,就通过对象(尚未创建)将值返回到Main cpp。 If that makes sense? 如果这有道理?

Ive been trying to wrap my head around this for a few hours now and I just cant seem to get it right, was hoping someone here would point me in the right direction? 我一直试图绕过这几个小时,我似乎无法把它弄好,希望有人在这里指出我正确的方向?

Thank you in advance, and sorry for the messy code.. 提前谢谢你,对于凌乱的代码感到抱歉..

It's an acceptable start. 这是一个可以接受的开始。 But there are a couple of issues here. 但这里有几个问题。

Let's go through the header first: 我们先来看看标题:

You need to get rid of the #include of a cpp file. 你需要摆脱cpp文件的#include You should only include headers in a header. 您应该只在标头中包含标头。 And better limit yourself to the headers really required by the code in the header. 最好将自己限制在标题中代码所需的标题中。 For instance, <iostream> is not really needed for the class definition. 例如,类定义并不真正需要<iostream> So move this include to the cpp where it is needed. 因此将此包含移动到需要它的cpp。

You also need to get rid of the using clause: this should be used in cpp, and not in headers, because it causes the file including the header to ignore that another namespace is imported, which could later on create conflicts (in larger projects). 你还需要摆脱using子句:这应该在cpp中使用,而不是在头文件中使用,因为它会导致包含头文件的文件忽略导入另一个命名空间,这可能会在以后创建冲突(在较大的项目中) 。 More advices on how to use headers here . 有关如何在此处使用标头的更多建议。

Then a Triangle is a class and not a function. 然后Triangle是一个类而不是一个函数。 So you have to define it with class Triangle { ... }; 所以你必须用class Triangle { ... };定义它class Triangle { ... }; and not class Triangle() {...}; 而不是class Triangle() {...};

I also would expect the following member functions to be public: 我还希望以下成员函数是公开的:

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

Now to the implementation 现在来实施

First, you need to avoid the confusion between member variables and member functions: 首先,您需要避免成员变量和成员函数之间的混淆:

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

Then you need to declare the variables that you use: 然后你需要声明你使用的变量:

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

Then you can just return a boolean expression. 然后你可以返回一个布尔表达式。 No need to be more explicit: 无需更明确:

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

Finally, your set function needs some rework: you have to return true or false . 最后,你的set函数需要一些返工:你必须返回truefalse You better do not use cout in the return statement, but before returning. 你最好不要在return语句中使用cout ,但在返回之前。 Last but not the least, you must perform the test of validity before you assign the member variables. 最后但并非最不重要,您必须在分配成员变量之前执行有效性测试。

Finally to main() 最后到main()

Input and output stream are different things. 输入和输出流是不同的东西。 So do not try <<endl on cin ! 所以不要尝试<<endl on cin!

Once the input work, you can use t.set(...) to use the values entered by the user to change t. 输入工作后,您可以使用t.set(...)来使用用户输入的值来更改t。

If the t.set(...) returns true, you can display the result of the functions. 如果t.set(...)返回true,则可以显示函数的结果。 For example: 例如:

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

If the result is false, then better inform the user that you can't do no more things with such a triangle. 如果结果为假,则更好地告知用户您不能再使用这样的三角形。

I suppose that you know for the compilation how to compile the main.cpp and triangle.cpp together. 我想你知道编译如何编译main.cpp和triangle.cpp。

1) Include header files, not cpp files! 1)包括头文件,而不是cpp文件!

Remove: 去掉:

    #include "Triangle.cpp"

reason: 原因:

cpp files are what gets compiled. cpp文件是编译的。 They depend on header files, not the other way around. 它们依赖于头文件,而不是相反。 headers can depend on other headers, that happens a lot actually. 标头可以依赖于其他标头,这实际上发生了很多。 but they shouldn't ever depend on a cpp file. 但他们不应该依赖于cpp文件。

2) Wrap headers in ifndef/define blocks. 2)在ifndef / define块中包装头。

Move: 移动:

#ifndef TRIANGLE_H and #define TRIANGLE_H to the top of the file above everything else. #ifndef TRIANGLE_H#define TRIANGLE_H到文件的顶部,高于其他所有内容。 Stylistically you may want to comment what the file does above the ifndef/define block instead of under 在风格上你可能想要评论文件在ifndef / define块上面而不是在下面的内容

Example: 例:

    // 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

Reason: 原因:

In C++ you can think of the line: #include <iostream> as copy-pasting the contents of the iostream file overtop of that line. 在C ++中,您可以想到以下行: #include <iostream>将iostream文件的内容复制粘贴到该行的上方。 So when you #include "triangle.h" in both main.cpp and triangle.cpp, you're describing what the triangle class will look like to each of those cpp files. 因此,当您在main.cpp和triangle.cpp中#include“triangle.h”时,您将描述三角形类对每个cpp文件的外观。 main.cpp needs to know so it can create and use a triangle, and triangle.cpp needs to know so it can implement the functions in Triangle correctly. main.cpp需要知道它可以创建和使用三角形,而triangle.cpp需要知道它才能正确实现Triangle中的函数。

If you include a file twice, that file is effectively copy-pasted twice. 如果您包含两次文件,则该文件将被有效地复制粘贴两次。 Normally that would be re-defining its contents, which would be a compile error. 通常,这将重新定义其内容,这将是编译错误。 What the ifndef/define block does is say "hey, if TRIANGLE_H isn't already defined, this is the first time it's been included. So go ahead and define TRIANGLE_H, along with all the file contents. The next time triangle.h is included we'll see that TRIANGLE_H is already defined and we skip right by the contents of that header, instead of re-defining what a Trinagle is. ifndef / define块的作用是“嘿,如果尚未定义TRIANGLE_H,这是它第一次被包含。所以继续定义TRIANGLE_H,以及所有文件内容。下一次triangle.h是包括我们将看到TRIANGLE_H已经定义,我们跳过该标题的内容,而不是重新定义Trinagle是什么。

The reason I suggest you move it to the top, is you're including iostream, triangle.cpp (we talked about that part already) and using namespace std every time triangle.h is included. 我建议你把它移到顶部的原因是你包括iostream,triangle.cpp(我们已经讨论过那个部分)并且每次包含triangle.h时都使用命名空间std。 There's no need for that. 没有必要这样做。

3) Fix the triangle class declaration 3)修复三角类声明

Change: 更改:

    class Triangle(){

to

    class Triangle {

Reason: 原因:

You're close! 你很亲密! but you're confusing the syntax of declaring a constructor with the syntax of declaring a class. 但是你混淆了使用声明一个类的语法来声明构造函数的语法。

4) Make functions you intend to use outside of Triangle public. 4)使您打算在Triangle公共之外使用的功能。

Move: 移动:

the "public:" access specifier above double Perim(); double Perim();上面的“public:”访问说明符double Perim();

Reason: 原因:

If you want to call the methods: Perim, Area and IsRect from main.cpp (or from anywehre but the inside of the triangle class!) you'll need those methods to be public. 如果你想调用方法:来自main.cpp的Perim,Area和IsRect(或者来自anywehre但三角形类的内部!)你需要将这些方法公开。

You might be tempted to make everything public, but it's bad form - and your instructor specifically said "encapsulate a, b, c". 你可能想把所有东西都公之于众,但这种形式很糟糕 - 你的导师专门说“封装a,b,c”。 You can google the encapsulation design pattern to understand why. 您可以谷歌封装设计模式来了解原因。 I won't get into it here. 我不会在这里介绍它。

5) Fill out your triangle constructor 5)填写三角形构造函数

See the method: 看方法:

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

Changes: 变化:

  • In the header file you don't give the three parameters names. 在头文件中,您不提供三个参数名称。 This isn't an error, but it's weird. 这不是一个错误,但它很奇怪。 You should probably give those parameters names. 您应该给出这些参数名称。

  • In your other constructor (the one without parameters) you show that you know how to assign a, b, and ca value! 在你的另一个构造函数(没有参数的构造函数)中,你表明你知道如何分配a,b和ca值! Go ahead and assign them values in this method. 继续并在此方法中为它们分配值。

  • Consider if you actually want to use int as the types of the parameters. 考虑一下你是否真的想使用int作为参数的类型。 You're storing the side lengths as doubles but you're providing them to the constructor as ints. 您将边长存储为双精度,但是您将它们作为整数提供给构造函数。 This isn't an error, but it's weird. 这不是一个错误,但它很奇怪。

6) Fix the body of the Set method. 6)修复Set方法的主体。

See the method: 看方法:

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

Note: 注意:

Remember a method is an exchange. 记住一种方法是交换。 You provide it with it's parameters, it does some work and it returns to you some value (unless it 'returns' void). 你提供它的参数,它做了一些工作,它返回给你一些价值(除非它'返回'无效)。 Your method is asking for 3 doubles, and returning a bool. 你的方法是要求3个双打,并返回一个布尔。 If you're returning a bool, you're agreeing to give back a true or false value. 如果你要归还一个布尔,你就同意给出一个真值或假值。 Here you're tring to return whatever cout << "..."; 在这里,你要回报任何cout <<“......”; returns. 回报。 That doesn't sound like what you want (even if it compiles). 这听起来不像你想要的(即使它编译)。 You don't care about what cout returns, right? 你不关心cout什么回来,对吧?

Changes: 变化:

Don't cout anything from this function. 不要在这个功能上做任何事情。 Just return true if a triangle is possible, and false if it's not possible. 如果三角形可能则返回true,如果不可能则返回false。 You can cout whatever you want from where Set is being called from. 你可以从调用Set的地方cout你想要的任何东西。

7) Encapsulate a, b, c. 7)封装a,b,c。

You've made ab and c private. 你把ab和c私有化了。 That's half of encapsulation. 这是封装的一半。 Your instructor probably wants you to write a getter and setter for these variables in Triangle. 您的教师可能希望您在Triangle中为这些变量编写一个getter和setter。

Example: 例:

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

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

I'll leave it as an exersize to do the rest. 我会把它留作exersize来做其余的事情。

8) Using your Triangle in main.cpp 8)在main.cpp中使用你的三角形

If you take your local variable t , you can call functions on it like so: 如果你使用局部变量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

With that information, after you're done your calls to cin to get the user inputs, do the following: 有了这些信息,在您完成对cin的调用以获取用户输入后,请执行以下操作:

  • create a boolean variable to store the result of set, we'll use this later. 创建一个布尔变量来存储set的结果,稍后我们将使用它。
  • call the Set function on t, providing the 3 lengths the user inputted. 在t上调用Set函数,提供用户输入的3个长度。 Store the return of Set in our boolean. 在我们的布尔值中存储Set的返回值。
  • Write an if statement. 写一个if语句。 Check if the value of that boolean is true. 检查该布尔值是否为true。 If it is, print "A triangle with these parameters is possible.", otherwise print "A triangle with these parameters is NOT possible." 如果是,则打印“可以使用具有这些参数的三角形。”,否则打印“不能使用具有这些参数的三角形”。
  • If your assignment requires you to do anything else or anything different, such as printing the result of Perim, Area and isRect, do that! 如果你的作业要求你做任何其他或不同的事情,比如打印Perim,Area和isRect的结果,那就去做吧!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM