How should I write classes? C++

2019-06-06 11:59发布

问题:

Hey.. I don't really get them. I read a tutorial about classes in C++, and I don't get a few things: In every example and tutorial that I've seen, functions are never written inside the class! For example, why write a class like this:

#include <iostream>

using namespace std;

class test
{
    private:
        int x, y;
    public:
        test (int, int);
        int tester () {return x + y; }
};

test::test (int a, int b)
{
    x = a;
    y = b;
}

int main()
{
    test atest (3, 2);
    test atest2 (2, 6);

    cout << "test1: " << atest.tester() << endl;
    cout << "test2: " << atest2.tester() << endl;

    return 0;
}

or like this:

#include <iostream>

using namespace std;

class test
{
    private:
        int x, y;
    public:
        void set_values (int,int);
        int testfunc () {return x + y; }
};

void test::set_values (int a, int b)
{
    x = a;
    y = b;
}

int main()
{
    test tester;

    tester.set_values (3, 2);

    cout << "test1: " << tester.testfunc() << endl;

    return 0;
}

instead of simply like this:

#include <iostream>

using namespace std;

class test
{
    public:
        int tester (int x, int y) { return x + y; }
};

int main()
{
    test atest;

    cout << atest.tester(3, 2) << endl;

    return 0;
}

Honestly, I just don't get it!

Why do I need private members??

When and how should I use destructors?

How should I generally write my classes?

I'm very confused here and I really need somebody to clear up things for me... thanks

回答1:

The example plausibly separates out the setting and retrieving of values because there's more in-between those than you see in the given main function. If there wasn't, you're completely right that you should combine them, and even eliminate the class in favor of a free function.

For example, the code could look something like:

void example(Test obj) {
  if (something) {
    process(obj.tester());
  }
}

int main() {
  int x, y;  // Imagine these are assigned to user input.
  Test obj (x, y);
  example(obj);  // Obj.tester may or may not be used.  If the x + y was not
  // separated, then you couldn't "maybe use" it.
  return 0;
}

Why do I need private members?

You don't. They're more documentation than anything else. Accessibility (public/protected/private) is documentation which is checked by the compiler, however. This check is helpful mostly in order to encapsulate values, but encapsulation is much, much more than just marking something as non-public. For example, if you (from a public method) return a reference to a non-public data member, you've tied the implementation of that member to the class' public interface.

When and how should I use destructors?

When you need special destruction logic. Read about the Rule of Three. Write them as if they were a class method named "~" plus the class name, taking no parameters and omit a return type (even void), similarly as for ctors.

How should I generally write my classes?

You don't have to define the methods outside of the class. In fact, implement all methods inside the class to start out with, then move the methods out as there is a need. This is much harder to screw up while you learn the important basics of the language, and much more convenient for the types of classes you'll write initially. Use ctor initializers when they are just as feasible as assignment within the ctor body.

struct Test {
  Test(int x, int y)  // Use the same names rather than inventing 'a' and 'b'.
  : _x (x), _y (y)
  {}

  int tester() const { return _x + _y; }
  // Move outside the class when needed, if at all -- and it won't be needed
  // for a function like this.
  // Because this doesn't modify anything, it's suitable to be const, which
  // means it can be called on a const Test object.

  int _x, _y;
  // Technically public, but with a "non-public name".  Mark private as you
  // wish, or as the design settles down.
};

Note I've used "struct" to declare this class instead of "class". The result is identical, except I get to skip "public" on any base classes (there are none here, but bases are more often public than not) and the default member accessibility is "public" too: this results in shorter and slightly more clear code.



回答2:

As Greg says you really need to read a book.

How should I generally write my classes?
Classes let you combine data and functions that act on them into one thing.

Why do I need private members??
Private members can only be accessed by functions in your class, this lets you control how data is stored in the class without the user of the class being able to do things you don't expect.

When and how should I use destructors?
When you have something that needs to be cleaned up when you object is no longer needed, a file closed or memory released.



回答3:

Private members hide the internals of the class from manipulation from outside. This allows the writer of the class to change internal implementation details without worrying about breaking other code, and allows the class to ensure that it stays in a valid state. (Consider a triangle with leg lengths as public data members: there would be no way to prevent some other code from setting leg lengths to 2, 3, and 7.)

A destructor should generally deallocate resources held by the object - things like file handles, database connections, memory blocks on the heap. If the object doesn't have resources like that, it usually doesn't need you to write a destructor. If it does, you probably also need to write your own copy constructor and assignment operator. (It's possible to use "smart pointers" to refer to memory blocks, and they have their own destructors built in.)

You should write your classes by figuring what the objects are supposed to do. Then, write function declarations that allow callers to do those things. This gives you the public interface of the class, so those functions should be public:. Then, write everything you need to implement these functions. This will almost certainly involve data, and likely will involve other functions that the public functions will call. These things should be private:.

In general, the class definition goes into a header file, and the header file should have as little in it as possible. A smaller header file means faster overall compilation times (since the header file will be #included by at least one code file), and reduces what other people, or you six months later, have to read to understand what the class does. Implementations go in a code file.



回答4:

Why do I need private members??

Private members allow you to enforce class invariants. Say your class represents a bank account, you want to be able to enforce the idea that you can't have negative money in your account. The class can't guarantee that if any code out there can modify the account balance. Make the account balance private then the class can guarantee that the property holds.

When and how should I use destructors?

You use destructors to Release resources the class holds, sockets, db connections, memory. Something to be aware of is the rule of three. That is if you have a non trivial constructor you more than likely need a destructor and a copy constructor.

How should I generally write my classes?

General guide lines for class writing would be follow the SOLID principles.



回答5:

When you get into the driver seat of a car, you have certain expectations of how to operate that car. Turning the wheel to the left should turn the car to the left. Pressing the gas pedal should make it go faster, and pressing the break pedal should slow it down. As the driver, you are entitled to make these assumptions because the world has standardized the interface through which you operate the vehicle.

So, what if you are driving an electric car instead of a combustion engine car? Should the wheel and/or pedals be changed? Of course not! It's silly to change the controls just because some technical component of the car is different. It shouldn't matter whether the car is powered by gas, electricity, water, hamsters, or sheer will power; turning the wheel to the right should make the car go right!

When it comes to designing an object, the public functions act as the interface to the programmer. The programmer can have general assumptions that certain function calls will produce certain kinds of results. Continuing the car analogy, good public functions would be accelerate(), turnWheel(), toggleLights(), etc. A bad public function would be fuelInjection(). Why is the driver concerned with operating that particular component? The car should be handling those details! Good private members would be fuelInjection(), exhaust(), etc.

The car analogy breaks down after a while, so let's look at a more practical example. Let's say you're making an image class. How do you imagine interacting with a good image object? Like this?

Image i;
i.loadFromFile("myFace.jpg");

Or like this?

Image i;
i.preparePixelBuffer();
memset(i.pixelBuffer, 0, i.pixelBufferSize);
FILE* fp = fopen("myFace.jpg", "r");
bool doneLoading = false;
while (!doneLoading)
...

Never use objects/classes "just because". Think of a focused concise behavior that you want wrapped up into a class. It will make your life much easier!



回答6:

Should I define methods in the class body? Why do I need private members?

As Fred said, its often easier to do so when learning, playing around with code, or even as a professional as a first draft or other circumstances. Once specific fact to note is that is the class body definitions are automatically 'inline', which means the compiler insert the code at the calling point and may avoid a function call overhead.

The underlying principle of both splitting the methods from the body and private members is that of encapsulation, or coupling/cohesion. This means that other code which uses the class is only interested in what it claims to do (interface), not how it does it (implementation). This is useful in two main ways:

  1. When writing client code we can focus better on things that matter.
  2. If we have to fix the implementation, we have a good chance of not breaking client code.

Ultimately, all this boils down to trying to solve the problem in software engineering of how to break down large systems into components so as to have a managable code base. C++ allows you define interfaces using the public part of class bodies and implementation as the private section or .cpp file. This reduces the overall coupling in the system and hence its overall complexity.

When and how should I use destructors?

An example of of the encapulsation concept is the objects "own" resources. Any resource thing the object creates it is also responsible for releasing. When the object is destroyed, it therefore needs to free remaining resources. Now, often for simple objects you do not have to explicity do anything. The main case for a new programmer will be calling 'delete' on objects created using 'new'. It's useful to avoid having to do this explicity using smart pointers, such as std::auto_ptr<>.

How should I generally write my classes?

Definitely make sure you understand how to split code into the .cpp file. Having done that, for self learning you will be fine with code in the class body. What you might find is that the class body becomes long and hard to navigate. That's a sign that its now take the time to split it up. Another good case for splitting things up is when the implementation is "interesting". Suppose you have a drawing class that is implemented using OpenGl. Putting the details in the .cpp file means the rest of your code does not end up including the OpenGl header files.



回答7:

Traditionally, methods that are defined inside the class definition are inline. That is, no call is made when they are executed. However, with newer compilers the rules about inlining are more complex. However, I think a good rule of thumb is still to define methods in the header that you would want inlined.

You don't need private members. Classes provide a way to organize your code into a logical unit. By making members private, you encapsulate that logic within your class. The benefit is that you are able to focus on those private members without worrying about what other parts of your application does because no other part of the application will directly access those members.



回答8:

The first style of writing, as shown above, allows you to separate the function definitions (your class interface) into a header file and the function declarations (your class implementation) into the .cpp file. You can learn more about header files in this question. There are benefits to inlining some methods, and one way you do that is to write the function declarations in the class, but to gain those benefits your method must meet several criteria.

Private members allow you to hide the data of your class so that only that class can manipulate that data. It provides a way to handle proper encapsulation, and important object oriented programming concept. Encapsulation bundles all of the methods that operate on some piece of data into a single class, which happens to potentially facilitate nice, clear designs in software.

There is more about the destructor in this question. If you are confused about the C++ destructor, you might want to read up on memory in C++ in a good C++ book such as Accelerated C++.



回答9:

You actually need to study some more! lets start with members private member means that you can access it, read it, change it in any way from only withing the class protected member means the same but you can also access it through inheritance (read inheritance really later) public means... well, that you can access it from any were you want. In small programms this does not matter but if you are in a team with 10 or 100 programmers you propably want some things to be left as is and not being able to change everything you want.

classses are written this way because that is the way of C++ the truth is that the part where you define your class -> class square{}; is the desrciption of the class. you design your class and define the class members. and then after the compiler knows what member is of what class then it goes to the actual imlementation and uses the actual members it will be better for you to understand if you use .h files in your program a header is where you design your clash and then on the cpp which includes the .h you actually impliment the methods and values of the variables

and the best part is destructors. You need destructors to delete objects when an instance of a class gets deleted. Deletion of objects is part of programming that needs a good basis on memory allocation and deallocation. i have to suggest a book which helped me a lot book : "Thinking in C++" my advise is, keep coding no matter what! if you get stack on something try to find examples, if you still cant solve the problem, take a break and try again later

Enjoy!



回答10:

A lot of folks have said you need to split up your class into a .h file and a .cpp file. Which is usually done by hobby programmers because it helps make huge classes a lot smaller to negotiate when you look back at them to see what they do. Having all the code that makes that class actually work in the same file as all the functions/data members you can use, makes it really hard to see how you can actually 'use' the class.

Essentially, it lets you just look at the header file once it's finished, and forget how the class actually works under the hood! At least, that's the goal. When you get into professional programming, or just really big projects, it also helps with compile times, separating how it works from folks who code with you who don't need to bother with it, etc.

Private members are to protect your future self from your past self mostly. So that... say, you write a class that has a method that returns how much money an employee has.

int Employee::GetDollars(int employee_id); 

you call it. All it does it return the private 'int dollars[]' data variable in the class, maybe along the lines of 'return dollars[employee_id];' Now in the future, if you change how you figure out which employee_id gets which employee or whatever, you only gotta change it in one place. Instead of if you just used classname.dollars[id], because then you'd have to change it at every single point in your program you ever used it!