How should I write classes? C++

2019-06-06 11:37发布

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

10条回答
Deceive 欺骗
2楼-- · 2019-06-06 12:14

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

查看更多
叼着烟拽天下
3楼-- · 2019-06-06 12:15

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.

查看更多
神经病院院长
4楼-- · 2019-06-06 12:19

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.

查看更多
做自己的国王
5楼-- · 2019-06-06 12:21

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!

查看更多
Evening l夕情丶
6楼-- · 2019-06-06 12:24

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.

查看更多
一夜七次
7楼-- · 2019-06-06 12:24

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!

查看更多
登录 后发表回答