Explain blank class functions in C++

2019-08-08 21:31发布

问题:

class forums : public master{
public:
    forums() : next(0),prev(0) {}
}
  1. Please Explain what exactly does the functions next(0) and prev(0) are meant?

  2. What does seperation of function with a comma (,) indicates? what's the effect of empty braces {}, next to these functions?

  3. I am a beginner in C++, and trying to figure out what does this means, or intended use for these way of writing function?

like is it specially meant for overriding?

回答1:

Short answer

That is a constructor with an empty body, and a member initialisation list that initialises two data members to the value 0.

i.e.

  • class-name([ ctor-args ]) [ : member-init-list ] { [ ctor-body ] }

  • where member-init-list is member-name(args) [, member-name(args) [, ... ] ].

(Note: not actual C++ lexical grammar constructions)


Long answer

Background

Take the following class definitions:

struct Base {};
struct Derived : Base {};

You may already be aware that Derived derives from Base.

You may also already be aware that Derived and Base both have a synthesised (implicitly-declared) default (takes no arguments) constructor. Derived's constructor implicitly/automatically invokes Base's.

Now let's add a basic member function:

struct Derived : Base {
   void foo() {}
};

I have both declared and defined this member function foo; its body is empty, so nothing happens when you invoke it. This is pretty pointless, but it's perfectly valid.

Now, instead, let's make our own constructor:

struct Derived : Base {
   Derived() {}
};

This looks more familiar. It's still a [special] function with an empty body, and the Base constructor is still being implicitly invoked. We haven't changed that.


Handling data members

Let's add some data members and set their value in our constructor:

struct Derived : Base {
   Derived() {
      x = 0;
      y = 0;
   }

   int x, y;
};

Both x and y will have the value 0 after object construction. This is still fundamental C++.

But what you may not be aware of is that you are not initialising these data members. You are merely assigning to them after the possibility of initialising them.

In fact, data members of built-in types are not implicitly initialised, so let's pick a better example:

struct Derived : Base {
   Derived() /* HERE */ {
      x = "";
      y = "";
   }

   std::string x, y;
};

x and y are implicitly initialised before the code in the constructor body runs. When the constructor body starts to run, all members that will be initialised, have already been initialised, and the base constructor has been implicitly invoked.

We can intercept this behaviour and provide our own initialisation values by writing a member initialiser list in the place where I wrote /* HERE */ in the previous snippet. With the member initialiser list, the snippet looks like this:

struct Derived : Base {
   Derived() : x(""), y("") {
      x = "";
      y = "";
   }

   std::string x, y;
};

Wow! OK; now we're initialising the strings to "", and later assigning the same, empty value to them in the constructor body. We can get rid of those assignments, then:

struct Derived : Base {
   Derived() : x(""), y("") {}

   std::string x, y;
};

Now the constructor body is empty, but the constructor still does stuff. It implicitly invokes the base constructor, and it explicitly initialises the data members x and y to the empty string.

And, because std::string has a default constructor that does the same, we can write for short:

struct Derived : Base {
   Derived() : x(), y() {}

   std::string x, y;
};

Going back to your original example, this applies to objects of built-in types just as easily. Let's consider two pointers:

struct Derived : Base {
   Derived() : next(0), prev(0) {}

   Derived* next;
   Derived* prev;
};

Handling base classes

And, as an added bonus, we can use the member initialisation list to invoke the base constructor explicitly:

struct Derived : Base {
   Derived() : Base(), next(0), prev(0) {}

   Derived* next;
   Derived* prev;
};

This is pretty pointless unless the base constructor wants some arguments:

struct Base {
   Base(int x) {}
};

struct Derived : Base {
   Derived() : Base(0), next(0), prev(0) {}

   Derived* next;
   Derived* prev;
};

I hope that this has been useful.



回答2:

What you have there is an "initialization list".

The code is setting the initial values of the next and prev members of the instance of the class.

That code might call constructor functions if next and prev are instances of classes, or might just assign values to them if they're primitive types.

They are comma-separated because that's how the syntax of initialization lists looks.

The empty braces signify the body of the forums constructor - nothing happens in the constructor itself in this example, because the work is done in the initialization list.



回答3:

1) It initializes next and prev to 0, as in initialization, not assignment.

2) That's known as a constructor initializer list. Without it, you'd need to assign next & prev to 0 in the constructor body. That's not the same thing. You need to understand the difference between object initialization and assignment. For some types, references and const objects, the initializer list is mandatory. For complex objects, you're better off using the initializer list because when assigning the object in the constructor body, you'll pay for the initialization of the object AND its assignation. For simple integral types, there's no difference but for types with constructors, there is, because typically, assignation is almost as expensive as initialization.

Here, the body is empty because only next and prev need initialization and nothing else needs to be done.

Also, the member initialization order is very strict, it occurs in the order of their declaration. The order in which you write it down in the initializer list does not matter, it happens in the declaration order.

So important, understand between initialization and assignation.

Also understand declarations vs definitions. Lots of confusion will arise if you don't understand these concepts.

3) It's basic object construction. There is an empty body because there must be a body; it just does nothing.



回答4:

See "initialization lists in C++"



回答5:

That's not a function. It has the same functionality as:

forums()
{
    next = 0;
    prev = 0;
}

next and prev are probably members of your base class.

There are however differences - for one, using initialization lists is faster than assigning values to members afterwards.