Content
Introduction to Classes and Member Functions Member Accessibility and Constructors <- Go BackUniversity of Michigan at Ann Arbor
Last Edit Date: 02/06/2023
Disclaimer and Term of Use:
We do not guarantee the accuracy and completeness of the summary content. Some of the course material may not be included, and some of the content in the summary may not be correct. You should use this file properly and legally. We are not responsible for any results from using this file
This personal note is adapted from Professor Amir Kamil, Andrew DeOrio, James Juett, Sofia Saleem, and Saquib Razak. Please contact us to delete this file if you think your rights have been violated.
This work is licensed under a Creative Commons Attribution 4.0 International License.
Different from C, C++ allows the data and function of an ADT to be defined together. It also enables an ADT to prevent access to internal implementation details, as well as to guarantee that an object is appropriately initialized when it is created.
We use struct
to define C-style ADTs and class
to define C++ ADTs.
A C++ class includes both member variables, which defines the data representation, as well as member functions that operate on the data. The following example is a Triangle
class in C++:
1 class Triangle { 2 double a; 3 double b; 4 double c; 5 6 public: 7 Triangle(double a_in, double b_in, double c_in); 8 9 double perimeter() const { 10 return this->a + this->b + this->c; 11 } 12 13 void scale(double s) { 14 this->a *= s; 15 this->b *= s; 16 this->c *= s; 17 } 18 }; 19 20 int main() { 21 Triangle t1(3, 4, 5); 22 t1.scale(2); 23 cout << t1.perimeter() << endl; 24 }
Try it out:
There are two ways to initialize a constructor in C++ class. Let's take the triangle class above as an example here.
Triangle(double a_in, double b_in, double c_in): a(a_in), b(b_in), c(c_in) {}
Note: The order of the initialization list does not matter (i.e. c(c_in), a(a_in), b(b_in) works the same, but some compilers will generate a warning if the order differs between the member declarations and the member-initializer list).
Tip: Use the initializer list whenever it is possible.
Triangle(double a_in, double b_in, double c_in){ this->a = a_in; this->b = b_in; this->c = c_in; }
Note: We can ignore this->
when writing a C++ class (i.e. a = a_in;
works the same as this->a = a_in;
). The complier will automatically add this->
for us.
However, in some cases we still need to use this->
. For example, if there are names in a closer scope that conflict with the member names:
class Triangle { double a; ... double set_side1(double a) { this->a = a; } };
Here, the unqualified a
refers to the parameter a
, since it is declared in a narrower scope than the member variable. We can still refer to the member a
by qualifying its name with this->
.
Let us compare the syltes of C and C++ ADTs.
void Triangle_scale(Triangle *tri, double s) { tri->a *= s; tri->b *= s; tri->c *= s; } |
class Triangle { void scale(double s) { this->a *= s; this->b *= s; this->c *= s; } }; |
Triangle t1; Triangle_init(&t1, 3, 4, 5); Triangle_scale(&t1, 2); |
Triangle t1(3, 4, 5); t1.scale(2); |
double Triangle_perimeter(const Triangle *tri) { return tri->a + tri->b + tri->c; } |
class Triangle { double perimeter() const { return this->a + this->b + this->c; } }; |
|
i. Member Accessibility
In C++ class, we give a set of members a particular access level by placing private:
or public:
before the members – that access level applies to subsequent members until a new access specifier is encountered, and any number of specifiers may appear in a class. The following is an example:
1 class Triangle { 2 private: 3 double a; 4 double b; 5 double c; 6 7 public: 8 Triangle(double a_in, double b_in, double c_in); 9 10 double perimeter() const { 11 return a + b + c; 12 } 13 14 void scale(double s) { 15 a *= s; 16 b *= s; 17 c *= s; 18 } 19 };
Note: With the class key word, the default access level is private. As a result, the private:
at the beginning of the Triangle
definition is redundant, and the following works the same:
1 class Triangle { 2 double a; 3 double b; 4 double c; 5 6 public: 7 Triangle(double a_in, double b_in, double c_in); 8 9 double perimeter() const { 10 return a + b + c; 11 } 12 13 void scale(double s) { 14 a *= s; 15 b *= s; 16 c *= s; 17 } 18 };
In this example, the members a
, b
, and c
are declared as private, while Triangle()
, perimeter()
, and scale()
are declared as public.
Private members, whether variables or functions, can be accessed from within the class, even if they are members of a different object of that class. They cannot be accessed from outside the class.
Try it out:
ii. Costructors
A constructor is similar to a member function, except that its purpose is to initialize a class-type object. In most cases, C++ guarantees that a constructor is called when creating an object of class type.
Triangle t1; // calls zero-argument (default) constructor Triangle t2(3, 4, 5); // calls three-argument constructor Triangle t3 = Triangle(3, 4, 5); // calls three-argument constructor
Examples with "uniform initialization syntax":
Triangle t4{3, 4, 5}; // calls three-argument constructor Triangle t5 = {3, 4, 5}; // calls three-argument constructor Triangle t6 = Triangle{3, 4, 5}; // calls three-argument constructor
The following example is not a valid call of constructor. Instead, it declares a function called t7
which returns a Triangle
.
Triangle t7();
Note: 1. Constructor do no have return type; 2. The name of the constructor has to be the same as the class name.
There are two methods to initialize constructors in C++:
Triangle(double a_in, double b_in, double c_in) { a = a_in; b = b_in; c = c_in; }
Triangle(double a_in, double b_in, double c_in) : a(a_in), b(b_in), c(c_in) {}
Default Initialization
If a class declares no constructors at all, the compiler provides an implicit default constructor. The behavior of this constructor is as if it were empty, so that it default initializes each member variable:
1 struct Person { 2 string name; 3 int age; 4 bool is_ninja; 5 // implicit default constructor 6 // Person() {} // default initializes each member variable 7 }; 8 9 int main() { 10 Person elise; // calls implicit default constructor 11 cout << elise.name; // prints nothing: default ctor for string makes it empty 12 cout << elise.age; // prints undefined value 13 cout << elise.is_ninja; // prints undefined value 14 }
If a class declares any constructors whatsoever, no implicit default constructor is provided:
1 class Triangle { 2 double a; 3 double b; 4 double c; 5 6 public: 7 Triangle(double a_in, double b_in, double c_in); 8 9 double perimeter() const { 10 return a + b + c; 11 } 12 13 void scale(double s) { 14 a *= s; 15 b *= s; 16 c *= s; 17 } 18 }; 19 20 int main() { 21 Triangle t1; // ERROR: no implicit or explicit default constructor 22 }
In this case, if we want our type to have a default constructor, we have to explicitly write one:
1 class Triangle { 2 double a; 3 double b; 4 double c; 5 6 public: 7 // explicit default constructor 8 Triangle() 9 : a(1), b(1), c(1) {} 10 11 // non-default constructor 12 Triangle(double a_in, double b_in, double c_in) 13 : a(a_in), b(b_in), c(c_in) {} 14 15 double perimeter() const { 16 return a + b + c; 17 } 18 19 void scale(double s) { 20 a *= s; 21 b *= s; 22 c *= s; 23 } 24 }; 25 26 int main() { 27 Triangle t1; // OK: explicit default constructor 28 }