answersLogoWhite

0


Best Answer

The only really essential characteristic is that every object of a class must have at least one constructor (besides a copy or move constructor) and must have a destructor. However it is not necessary to declare either if the compiler-generated default semantic provides the exact behaviour we require. There are some additional compiler-generated characteristics that, while not essential to every class of object, we need to be aware of.

If we do not provide any user-defined constructor for a class, X, the compiler will generate the following:

  1. Default constructor : X (void)
  2. Copy constructor: X (const X&)
  3. Move constructor: X (X&&)
  4. Copy assignment operator: X& operator= (const X&)
  5. Move assignment operator: X& operator= (X&&)
  6. Destructor: ~X (void)

A default constructor may include formal arguments other than void, provided all formal arguments are declared with default values.

There are two "rules" that determine which of the above will be generated by the compiler:

  • If we declare any constructor for a class, the default constructor is not generated (if we require a default constructor, we must declare one explicitly).
  • If we declare a copy operation, move operation, or a destructor for a class, no copy operation, move operation or destructor is generated.

Note: The second rule is partially enforced (as of C++11). For backward compatibility, copy constructors and copy assignments are generated even if a destructor is defined. However, that generation is deprecated in the ISO standard and you should expect a modern compiler to warn against it.

There are 5 situations where an object is either copied or moved:

  • As an object initialiser.
  • As the source of an assignment: x = y, where x is an existing object.
  • As a function argument.
  • As a function return value.
  • As an exception.

There are three ways to initialise a new object from an existing object:

  1. T x {y};
  2. T x (y);
  3. T x = y;

In all three cases, x is the new object (the one being initialised) while y is an existing object of the same type or of a type that has T as a public base. The first form is known as universal initialisation as it can be used anywhere an initialisation is required. The second form can be used anywhere a universal initialisation can be used, but is predominantly used to differentiate between an initialiser-list constructor and an "ordinary" constructor. The third form can only be used as an in-class initialiser. The following shows all forms of initialisation (only one in each group can actually be used).

class X {

// in-class initialisations

int i {0}; // ok

int i (0); // ok

int i = 0; // ok

// constructor initialisation lists

X (int ii): i {ii} {} // ok

X (int ii): i (ii) {} // ok

X (int ii): i = ii {} // compiler error: cannot use = in a constructor initialisation list!

};

An "ordinary" constructor is any constructor that accepts one or more non-default arguments besides a copy or move constructor. Conversely, initialiser-list constructors are typically used to initialise containers with element values. The following demonstrates the difference:

std::vector a {42, 1}; // a container of 2 elements where a[0]==42 and a[1]==1

std::vector b (42, 1); // a container of 42 elements all initialised with the value 1

For consistency, universal initialisation is the preferred form (it makes it clear that an initialisation is taking place) unless we explicitly need to differentiate, as shown in above example. The third form should generally be avoided as it looks more like an assignment when it's actually an initialisation, however old habits die hard so we often use it in trivial initialisations, particularly with built-in types:

int main () {

int x = 42; // int x {42} is the preferred method

// ...

}

The difference between copy and move operations is that when we copy we create two independent objects with the same value as the source object. Thus x=y assures us that x==y when the copy is complete. When we move, x takes "ownership" of y's original value while y is left in a moved-from state. The moved-from state is non-specific, but it must be valid because the assumption is that y will fall from scope and must be in a valid state to do so.

When passing objects to functions by value, the object's copy constructor is always considered first. If no copy constructor is defined, the move constructor is used instead. But if neither copy or move is defined, objects of that class cannot be passed by value, they can only be passed by reference.

Conversely, when returning an object from a function by value, the move constructor is always considered first. If there is no move constructor, the copy constructor is used instead. But if neither exists, objects of that class cannot be returned by value, they can only be returned by non-local reference.

If an object has a copy or move constructor, it should also have a corresponding copy or move assignment operator. Not all objects are intended to be copied or moved, however most will support either or both. The difference between copy (or move) construction and copy (or move) assignment is that the constructor instantiates a new object from an existing object's value while an assignment assigns an existing object's value to an already-existing object. Assignment introduces the possibility of self-assignment, where an object's value is assigned to the same object. Self-assignment is a rare case, but we often have to guard against it. Consider the following:

void f (T& x, T& y) {

x = y;

}

In the above example, there is a possibility (however rare) that x and y may refer to the same object. If we look at a naive implementation of the move assignment operator we can better understand the problem:

class T {

int* ptr;

public:

T& operator= (T&&); // move assignment

// ...

};

T& T::operator= (T&& other) {

delete this->ptr;

this->ptr=other.ptr;

other.ptr=nullptr;

}

Here, an object of type T "owns" the resource pointed to by this->ptr and the intention is to move ownership of other.ptr to this->ptr. In order to take ownership of a another resource, we must first release the existing one, so we delete this->ptr. But what if other and this are the same object? This means that the resource referred to by other->ptr is also deleted -- they are one and the same resource -- the very resource we wanted to take ownership of! So when we assign other.ptr to this->ptr, we're left referring to the same invalidated memory we originally referred to. And when we assign nullptr to other.ptr, this->ptr is also assigned the nullptr, thus this->ptr is not referring to anything. To avoid this problem, we must guard against self-assignment:

T& T::operator= (T&& other) {

if (this == &other) return; // sanity-check!

delete this->ptr;

this->ptr=other.ptr;

other.ptr=nullptr;

}

Self-assignment guards are commonly referred to as sanity-checks, because the code would be insane without it and we simply cannot reason code that is insane.

Not all classes require self-assignment sanity checks when copying or moving via assignment. If our code can be reasoned such that self-assignment has no "side-effects", then we do not need to guard against it. Indeed, it would be a design-error to provide a sanity-check in the absence of side-effects, because self-assignment is (or should be) a rare occurrence, and a sanity-check would incur an overhead in all but those rare cases. Thus we only require sanity checks when we have side-effects to guard against.

Constructors and destructors interact correctly within class hierarchies. Constructors build objects "from the bottom up":

  1. Invokes base class constructors in the order they are declared.
  2. Invokes member constructors in the order they are declared.
  3. Invokes its own constructor body.

Destructors "tear down" an object in the reverse order it was constructed:

  1. The destructor executes its own body.
  2. Invokes its member destructors.
  3. Invokes it base class destructors.

When a class declares a virtual method, this tells us that the class is intended to be used as a base class and that objects of the class have polymorphic behaviour. That is, we can invoke that method, we may not know the runtime type of the whole object, we only know its base class, however the most-derived override of that method will be invoked automatically thus ensuring correct behaviour. Any class that has a virtual method must also have a virtual destructor, because if any of its bases are explicitly destroyed, the most-derived class destructor must be invoked first to ensure the object is destroyed "from the top down", even if we do not know the runtime type of that object.

User Avatar

Wiki User

7y ago
This answer is:
User Avatar

Add your answer:

Earn +20 pts
Q: What are the essential characteristics of an object in c plus plus?
Write your answer...
Submit
Still have questions?
magnify glass
imp
Continue Learning about Engineering

Is c plus plus 100 percent object oriented?

No; C++ is not 100% object oriented.


What is the difference between c and c plus plus extension?

c language is the structure oriented language and c does not follows the object oriented paradigms . c++ obeys the all object oriented language characteristics ========== C++ is a set of extensions to the C language to allow some (not all) principles of object-oriented programming to be used. Originally, C++ was a front end pre-processor for C and C++ compilers will translate C language functions.


Is c plus plus an object oriented language or an object based language?

C++ is object-oriented. It is not object-based because, like C before it, C++ supports the principal of primitive data types, which are not object-based.


What is the different of c and c plus plus?

c is procedure oriented and c++ is object oriented & much newer.


Can you use c in c plus plus without using class and object?

Sure.

Related questions

What is the role of object in c plus plus?

An object in C++ is an instance of a C++ class.


Which is best C or C plus plus?

depends what you use it for. c++ = object oriented c = not object oriented


Is c plus plus 100 percent object oriented?

No; C++ is not 100% object oriented.


What is the difference between c and c plus plus extension?

c language is the structure oriented language and c does not follows the object oriented paradigms . c++ obeys the all object oriented language characteristics ========== C++ is a set of extensions to the C language to allow some (not all) principles of object-oriented programming to be used. Originally, C++ was a front end pre-processor for C and C++ compilers will translate C language functions.


What is object in c plus plus?

An object is simply an instance of a class.


Is c plus plus an object oriented language or an object based language?

C++ is object-oriented. It is not object-based because, like C before it, C++ supports the principal of primitive data types, which are not object-based.


What is the significance of c plus plus?

C++ is an object oriented programming language


What is the different of c and c plus plus?

c is procedure oriented and c++ is object oriented & much newer.


Can you use c in c plus plus without using class and object?

Sure.


What do you call an object function in c plus plus?

method


What is 'this' pointer in c plus plus?

Address of the current object.


Why c plus plus is partially object oriented?

To allow backward compatibility and interoperability with ANSI C, which is entirely non-object-oriented.