C + + Basics (C++Primer learning)

Fundamentals of C + + (V)

C + + classes (Continued)

Supplement to the previous section:
When creating a class object, if the const keyword is added before the class name, the data in the created object cannot be modified.

const Stock num3("abc", 123, 212);  //A const object is created
num3.show(); //report errors

For const type class objects, the compiler cannot ensure whether the data members will be modified when calling member functions. Therefore, it is not allowed to write code like this. The solution is to use const keyword when declaring and defining class member functions.

void show() const;  //Declaration plus const keyword
void Stock::show() const{}  //When defining a function, add const keyword after parentheses

For C++11 and above compilers, the list initialization method is supported to initialize objects:

Stock ob1{param1, param2,param3...};
Stock ob2={param1, param2, param3..};

Are allowed.

1, this pointer
Referring to the example in the book, suppose you design a function (total_val) that needs to compare the maximum total price of two objects and return the larger object value.
First, declare the function inside the class:

const Stock& topval(const Stock& s) const;

This code may be difficult to read. Start from the left:
Const Stock & indicates that the return value type of the function (topval) is a reference to a const type Stock class.
The parameter type passed in by the function represented by topval (const Stock &) must be a reference to the Stock class
The last const means that the function can call a data member of const type without modifying its data.

Define the function outside the class:

const Stock& Stock::topval(const Stock& s) const
{
	if (s.total_val > total_val)
	{
		return s;
	}
	else
	{
		return *this;
	}
}

The use of this pointer is reflected here. For the type of return value of the above code, if the value returned is the value in the object, the this pointer will point to the object of the calling member.

num1.topval(num2);  //At this point, the this pointer points to the called num1 object
num2.topval(num1);  //The this object at this point points to the num2 object being called

Similarly, if you use the const keyword after the function bracket, you cannot modify the value of the object through the this pointer·
Because this is a pointer and what we return is not the address of the object, but the object itself, we need to add the dereference symbol *.
Notes:
An error is found when allowing the code, that is, when calling the show() function to display the information, the total stock price (total_val) always displays a strange number - 9.25596e+061. No matter how you change it, you can't. later, you understand that in the code we wrote earlier, the total stock price needs to be calculated through an inline function, and we didn't initialize the variable total_val during initialization. Here, modify the constructor and execute the set_total function in the constructor OK, just one more time.

Stock::Stock(const string &co, long sh, double share_v)
{
	company = co;
	shares = sh;
	share_val = share_v;
	set_total();
}

2, Object array
In practical applications, we usually need to create multiple objects, so it is more convenient to put the objects in an array for management.
When creating an object array, if the class of the object uses the default constructor, it can be defined as follows:

 Stock  ob_list[10];

Create an object array with ten objects of Stock class.
If we define our own constructor, like the Stock class, we need to initialize the object when creating the object:

Stock list[2] = {
	Stock("dd",1,2),
	Stock("ss",2,3)
	// Two objects were created
};

The member functions in the object can be accessed by subscript plus

Stock list[2] = {
	Stock("dd",1,2),
	Stock("ss",2,3),

};
list[1].show();

Note: the second object is accessed here because the subscript of the first object is 0
For classes with multiple overloaded constructors, different initialization methods can also be used in the list.
If the number of list objects created is more than the number of initialization objects, the remaining object compilers will use the default constructor (if there is no custom constructor, otherwise an error will be reported)
Ten objects, only two initialized:

Stock list[10] = {
	Stock("dd",1,2),
	Stock("ss",2,3),

};

report errors:
Create a const pointer to an array object:

const Stock* plist = &list[1];
const Stock& plist1 = list[0];
const Stock* p = &plist->topval(list[0]);

The first line is the pointer, the second line is referenced, and the third line creates a new pointer to receive the new object returned by topval.
You can see the difference between pointer and reference. Reference creates another name for the object, called plist1, which is not a simple shallow copy.

Stock list[2] = {
	Stock("dd",1,2),
	Stock("ss",2,3),

};
const Stock* plist = &list[1];
Stock& plist1 = list[0];
const Stock* p = &plist->topval(list[0]);
//cout << plist;
plist1.show();
list[0].buy(100, 20);
plist1.show();
list[0].show();

Through this code, you can verify that if you change the value of the source object, the value of the referenced object will also change. In fact, both names point to the same object.
Some thoughts on pointers: the type prefix in front of the pointer does not represent the type of the pointer, but the type of the object pointed to by the pointer; similarly, the type declaration defining the function does not represent the type of the function, but the type of the return value of the function

3, Scope of class
The scope of the name defined in the class is the whole class, so the name is known only in the class and unknown outside the class. In this way, even if different classes use the same class member name, it does not matter. Similarly, if you want to call resources inside the class, you must implement it through the object of the class.
Original text of the textbook: sometimes it is useful to make the scope of symbolic constants class, so it is a good idea to create a constant shared by all objects, but it doesn't work in practice:

class class
{
private: 
	const int param = 10;
	.....

The reason is that the class only describes the form of the object and does not create the object. Therefore, there is no space for storing values before creating the object. The following are two methods to realize this function:
1. Use enumeration to complete

class l class
{
private: 
	enum{Months = 12};
	double costs[Months];
....

Declaring enumeration in this way will not create class data members, and all objects do not contain enumeration. In addition, Months is only a symbolic name. When it is encountered in the code with the scope of the whole class, the compiler will replace it with a numerical value (12 in this case).
2. Use static keyword

class 2 class
{
private:
	static const int Months = 12;
......

This creates a constant named Months, which will be stored with other static variables rather than in objects.

4, Abstract data type
The Stock class is very specific. However, in practice, more general concepts are often expressed by defining classes. Create a stack class to illustrate this idea:

#pragma once
#include<iostream>

typedef unsigned long item;  //Using the typedef keyword can improve code portability


class Stack
{
private:
	enum{MAX = 10};
	item items[MAX];
	int top;
public:
	Stack();
	bool isempty() const;
	bool isfull() const;
	bool push(item& item);
	bool pop(item& item);
	void show();
};

On this basis, I added a display function to display the object content.
The function declaration is written in the. cpp file:

#include "stack.h"

Stack::Stack()
{
	top=0;
}

bool Stack::isempty()const
{
	return top == 0;  //Judge whether the equation is true. If it is true, it returns true. If it is not true, it returns false.
}

bool Stack::isfull()const
{
	return top == MAX; 
}

bool Stack::push(item& item)
{
	if (top < MAX)
	{
		items[top] = item;
		top++;
		/*l Another way of writing, more concise
		items[++top] = item;
		*/
	}
	else
		return false;
}

bool Stack::pop(item& item)
{
	if (top > 0)
	{
		item = items[--top];
	}
	else
		return false;
}

void Stack::show()
{
	std::cout << "the store is:";
	for (int i = 0; i < MAX; i++)
	{
		std::cout<<items[i];	
	}
	std::cout << '\n';
}

After reading the code, I felt that it was not comprehensive enough, so on this basis, I changed it myself, tried it several times, and felt comfortable. I encapsulated the process code using the class into a function.
First, the code functions using the class are also encapsulated in the class member function declaration file, so that the main function body is as simple as possible, and it is best to only call. The main purpose is to solve a circular input problem, and there are still many problems left 😁

Stack use_stack()
{
	Stack mystack;
	char ch;
	char temp;
	std::cout << "enter A to push to stack\n"
		<< "enter P to pop from stack, Q to quit.\n";
	while (std::cin >> ch && toupper(ch) != 'Q')
	{	
		while (std::cin.get() != '\n')
			continue; //Used to handle the Enter key
		switch (ch)
		{
		case 'A':
			std::cout << "push a word unless Q" << std::endl;
			while (1)
			{
				std::cout << "enter a word:";
				std::cin >> temp;
				if (temp != 'Q')
				{
					if (mystack.isfull())
					{
						std::cout << "stack full" << std::endl;
						break;
					}
					else
						mystack.push(temp);
				}
				else
					break;
			}
			break;
		case 'P':
			if (mystack.isempty())
			{
				std::cout << "satck empty" << std::endl;
			}
			else
				mystack.pop(temp);
			break;
		default:
			continue;
		}

	}
	mystack.show();
	return mystack;
}

In this case, there is only one line of code in the main function body:

int main()
{
	Stack mystack=use_stack();
......

But you have to declare this function in the main file, otherwise it won't work.
The display effect diagram is as follows:

Tags: C++ Javascript TypeScript

Posted on Sun, 05 Dec 2021 23:02:38 -0500 by nafarius1357