The compiler also creates a copy constructor if we don’t write our own copy constructor. Unlike the default constructor, the body of the copy constructor created by the compiler is not empty, it copies all data members of the passed object to the object which is being created.
Custom copy constructor can be really useful when there’s an array in a class and we want to deep copy it when passing value into a function.
Syntax:
1 2 3
Class_name(const Class_name& object){ ... }
To change =, the assignment operator, into deep copy, we need to overload the = operator as well.
Syntax:
1 2 3
operator=(const Class_name& object){ ... }
Since the content of the copy function and the overloading of the = operator is pretty much the same, we can write a private helper function to do the code reuse.
The extern keyword is used implicitly for functions. But to let the variable in one file be seen by other file, you should use extern for that file explicitly.
To specify to the compiler that a given member function is safe to call on const objects, you can declare the function with the const keyword. This specifies that the function is a “read-only” function that does not modify the object on which it is called.
1 2 3 4
const string& Person ::getName() const { return name; // Doesn ’t modify anything ; trying to modify a // data member from here would be a syntax error }
Static Members and Variables
Static data members of a class are also known as “class variables,” because there is only one unique value for all the objects of that class. Their content is not different from one object of this class to another.
For example, it may be used for a variable within a class that can contain a counter with the number of objects of the class that are currently allocated, as in the following example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include<iostream> usingnamespace std; classCDummy { public: staticint n; CDummy() { ++n; } ~CDummy() { --n; } }; int CDummy::n = 0; intmain(){ CDummy a; CDummy b[5]; CDummy* c = new CDummy; cout << a.n << "\n"; // prints out 7 delete c; cout << CDummy ::n << "\n"; // prints out 6 return0; }
#include<iostream> usingnamespace std; classNumber { private: int a;
public: Number(int a) : a(a) {} // here const is needed to declare that this method will not change member variable because the following overloading uses const intget()const{ return a; } }; Number operator+(const Number& a, const Number& b) { Number res(a.get() + b.get()); return res; } // notice, if you are defining this operator inside a class and if the operator needs 2 arguments, you only need to write 1. // This is because the first argument is the instance of the class calling the operator function. intmain(){ return0; }
#include<iostream> #include<vector> usingnamespace std; intmain(){ vector<int> v(10, 3); // 10 elements with value 3 v.push_back(1); v.pop_back(); cout << v.empty(); cout << v.size(); cout << v[4]; // use iterator to visit the elements vector<int>::iterator i = v.begin(); while (i != v.end()) { cout << *i; i++; } // or use auto for (auto j = v.begin(); j != v.end(); j++) { cout << *j << " "; } for (auto k : v) { // k is every element in v cout << k << " "; } // if you want to modify the vector, use reference for (auto& k : v) { k -= 1; cout << k << " "; } return0; }
Modifiers:
assign() – It assigns new value to the vector elements by replacing old ones
push_back() – It push the elements into a vector from the back
pop_back() – It is used to pop or remove elements from a vector from the back.
insert() – It inserts new elements before the element at the specified position
erase() – It is used to remove elements from a container from the specified position or range. v1.erase(v1.begin()+1,v1.begin()+3) for example.
swap() – It is used to swap the contents of one vector with another vector of same type. Sizes may differ.
clear() – It is used to remove all the elements of the vector container
emplace() – It extends the container by inserting new element at position
emplace_back() – It is used to insert a new element into the vector container, the new element is added to the end of the vector
count(v.begin(),v.end(),val) count how many element in v is equal to val.
find(v.begin(),v.end(),val) return iterator pointing to the first element equal to val
unique(v.begin(),v.end()) return an iterator pointing to the element after that remove all consecutive duplicates. But the size of the vector will not shrink, so it needs to be done like this:
A virtual function is a member function which is declared within a base class and is re-defined (overridden) by a derived class. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class’s version of the function.
#include<iostream> usingnamespace std; voidzero_small(int*, int*); voidzero_small(int&, int&); intmain(){ int a = 1, b = 0; cout << &a << endl; zero_small(a, b); return0; } voidzero_small(int& a, int& b){ cout << &a << endl; cout << "First input: " << a << endl; cout << "Second input: " << b << endl; if (a < b) { a = 0; } elseif (a > b) { b = 0; } cout << "First number: " << a << endl; cout << "Second number: " << b << endl; } voidzero_small(int* a, int* b){ cout << "First input: " << *a << endl; cout << "Second input: " << *b << endl; if (*a < *b) { *a = 0; } elseif (*a > *b) { *b = 0; } cout << "First number: " << *a << endl; cout << "Second number: " << *b << endl; }
The output is:
1 2 3 4 5 6
0x2fc65ffadc // notice that these two memory locations are the same 0x2fc65ffadc First input: 1 Second input: 0 First number: 1 Second number: 0
File I/O in C++ with fstream
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include<fstream> #include<string> intmain(){ std::ifstream in("in.txt"); /** * or * std::ifstream in; * in.open("in.txt"); */ int num; in >> num; std::ofstream out("out.txt"); out << num; std::string s; std::getline(in, s); return0; }
How to comment a custom function
Example code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/** * @brief Count the number of chess of the given type of disk * * @param board pointer to the board * @param disk disk type to be counted * @return number of disks having the same type as the input disk */ intcountBoard(Board board, Disk disk) { int cnt = 0; for (int i = 0; i < BOARD_SIZE; ++i) { for (int j = 0; j < BOARD_SIZE; ++j) { cnt += (board[i][j] == disk); } } return cnt; }
When using dynamic memory allocation, remember to time the size of the memory by sizeof(type)!!!!! This is true for all command: malloc, calloc, realloc, etc.
#include<stdio.h> #include<stdlib.h> intmain(void) { int *p1 = malloc(4*sizeof(int)); // allocates enough for an array of 4 int int *p2 = malloc(sizeof(int[4])); // same, naming the type directly int *p3 = malloc(4*sizeof *p3); // same, without repeating the type name if(p1) { for(int n=0; n<4; ++n) // populate the array p1[n] = n*n; for(int n=0; n<4; ++n) // print it back out printf("p1[%d] == %d\n", n, p1[n]); }