C++: Essay 6---new\delete\virtual method\abstract method

Pointer is a data type specially used to store memory addresses. (He stores not specific data but other people's addresses)

The common practice is to create a variable, then assign the address of this variable to a pointer, and then use the pointer to access the value of this variable.

In fact, in C and C++, we can allocate memory for related data without creating variables, that is, directly create a pointer and let it point to the newly allocated memory block.

int *pointer=new int;//int *pointer表示一个指向整型变量的指针,指针的名字叫做pointer,我们用new给他创建一个内存这个内存是什么类型呢?是int型。(整型的内存在现在的编译器一般是占用了4个字节的内存空间,那么这样定义的语句就是说声明一个指针变量,这个指针变量的名字叫做pointer,它指向一个整型的地址空间,用new给他创建出来,new事实上就是那个malloc这个函数的一个进化版本,都是差不多的只是对他进行了进一步的封装而已)
*pointer=110;//接着给这个指针,就是new出来的这块内存给他赋值,赋值为110
std::cout<<*pointer;//使用这个指针变量的值把他给打印出来
delete pointer;//最后删除这个指针,也就是释放了这一块new出来的内存。
//最后一步是非常必要和关键的,这是因为C和C++程序不会自动释放内存,程序中的每一个new操作都必须有一个与之对应的delete操作。

There are two ways to create an object, one is as follows here, the other is to use new.

Just remember, the grammar is written like this:

Class object (parameter);//The parameters in parentheses will automatically call the constructor to initialize this class.

http://c.biancheng.net/view/2221.html

#include<string>
#include<iostream>

class Pet
{
public:
	Pet(std::string theName);//构造函数
	void eat();
	void sleep();
	void play();
protected:
	std::string name;
};
class Cat :public Pet
{
public:
	Cat(std::string theName);
	void climb();
	void play();//对基类play的覆盖(在原有的基础上进行覆盖)
};
class Dog :public Pet 
{
public:
	Dog(std::string theName);
	void bark();
	void play();//对基类play的覆盖
};
Pet::Pet(std::string theName)
{
	name = theName;
}
void Pet::eat()
{
	std::cout<<name<<"正在吃东西"<<std::endl;
}
void Pet::sleep()
{
	std::cout << name << "正在睡觉" << std::endl;
}
void Pet::play()
{
	std::cout << name << "正在玩耍" << std::endl;
}
Cat::Cat(std::string theName):Pet(theName)//Cat的构造器继承Pet的构造器
{
}
void Cat::climb()
{
	std::cout << name << "正在爬树" << std::endl;
}
void Cat::play()
{
	Pet::play();
	std::cout << name << "正在玩球" << std::endl;
}
Dog::Dog(std::string theName):Pet(theName)//Cat的构造器继承Pet的构造器
{
}
void Dog::bark()
{
	std::cout << name << "正在叫" << std::endl;
}
void Dog::play()
{
	Pet::play();
	std::cout << name << "正在追赶那只猪" << std::endl;
}
int main()
{
	//第一种方法:创建对象
	//Cat cat("加菲猫");//这个Cat类实例化一个对象cat,取名叫做“加菲猫”。
	//Dog dog("小灰灰");
	//cat.eat();//使用指针的话就要用到->操作,而不能使用结构的.操作(点操作)。
	//cat.sleep();
	//cat.play();//先调用基类play()函数,再调用子类的play()函数
	//cat.climb();//此种创建对象方式可以使用

	Dog子类对象dog
	//dog.eat();
	//dog.sleep();
	//dog.play();//先调用基类play()函数,再调用子类的play()函数
	//dog.bark();//此种创建对象方式可以使用

	//第二种方法:指针方式创建对象
	//定义一个指针变量的形式来对它进行初始化
	Pet *cat = new Cat("加菲猫");//运行的时候才调用new,分配的是Cat类型的指针,给了cat,(为什么它可以用Pet来接受呢?因为Cat继承于Pet,所以使用Pet接受是没有问题的)
	Pet *dog = new Dog("小灰灰");//同上
	//Cat子类对象cat
	cat->eat();//使用指针的话就要用到->操作,而不能使用结构的.操作(点操作)。
	cat->sleep();
	cat->play();//此种方法创建对象:只调用基类play()函数,不再调用子类的play()函数
	//cat->climb();//此种Pet *cat = new Cat("加菲猫");创建对象方式:不能调用子类的该方法(但是我们明明在Cat子类里对play方法进行了覆盖)

	//Dog子类对象dog
	cat->eat();
	cat->sleep();
	cat->play();//此种方法创建对象:只调用基类play()函数,不再调用子类的play()函数。((但是我们明明在Dog子类里对play方法进行了覆盖,但实际上调用的是基类的play方法Pet::play()而不是两个覆盖的子类中的play()方法))
	//cat->bark();//此种Pet *dog = new Dog("小灰灰");创建对象方式:不能调用子类的该函数

	delete cat;
	delete dog;

	return 0;
}

The best point is the best point where the speed is the best and the most memory is saved.

Because cat and dog are pointers of the Pet type, they will definitely call the method of the Pet type, so that the execution speed is the fastest after optimization.

  

The version of the virtual method: (just need to add the virtual keyword before the play() function in the base class)

#include<string>
#include<iostream>

class Pet
{
public:
	Pet(std::string theName);//构造函数
	void eat();
	void sleep();
	virtual void play();//前边加上关键字virtual变成虚函数
protected:
	std::string name;
};
class Cat :public Pet
{
public:
	Cat(std::string theName);
	void climb();
	void play();//对基类play的覆盖(在原有的基础上进行覆盖)
};
class Dog :public Pet 
{
public:
	Dog(std::string theName);
	void bark();
	void play();//对基类play的覆盖
};
Pet::Pet(std::string theName)
{
	name = theName;
}
void Pet::eat()
{
	std::cout<<name<<"正在吃东西"<<std::endl;
}
void Pet::sleep()
{
	std::cout << name << "正在睡觉" << std::endl;
}
void Pet::play()
{
	std::cout << name << "正在玩耍" << std::endl;
}
Cat::Cat(std::string theName):Pet(theName)//Cat的构造器继承Pet的构造器
{
}
void Cat::climb()
{
	std::cout << name << "正在爬树" << std::endl;
}
void Cat::play()
{
	Pet::play();
	std::cout << name << "正在玩球" << std::endl;
}
Dog::Dog(std::string theName):Pet(theName)//Cat的构造器继承Pet的构造器
{
}
void Dog::bark()
{
	std::cout << name << "正在叫" << std::endl;
}
void Dog::play()
{
	Pet::play();
	std::cout << name << "正在追赶那只猪" << std::endl;
}
int main()
{
	//第一种方法:创建对象
	//Cat cat("加菲猫");//这个Cat类实例化一个对象cat,取名叫做“加菲猫”。
	//Dog dog("小灰灰");
	//cat.eat();//使用指针的话就要用到->操作,而不能使用结构的.操作(点操作)。
	//cat.sleep();
	//cat.play();//先调用基类play()函数,再调用子类的play()函数
	//cat.climb();//此种创建对象方式可以使用

	Dog子类对象dog
	//dog.eat();
	//dog.sleep();
	//dog.play();//先调用基类play()函数,再调用子类的play()函数
	//dog.bark();//此种创建对象方式可以使用

	//第二种方法:指针方式创建对象
	//定义一个指针变量的形式来对它进行初始化
	Pet *cat = new Cat("加菲猫");
	Pet *dog = new Dog("小灰灰");
	//Cat *cat = new Cat("加菲猫");
	//Dog *dog = new Dog("小灰灰");
	//Cat子类对象cat
	cat->eat();//使用指针的话就要用到->操作,而不能使用结构的.操作(点操作)。
	cat->sleep();
	cat->play();//此种方法Pet *cat = new Cat("加菲猫");创建对象再加上基类虚函数的方法:先调用基类play()函数,再调用子类的play()函数
	cat->climb();//这种Cat *cat = new Cat("加菲猫");创建对象方式:可以调用子类的该方法(但是我们明明在Cat子类里对play方法进行了覆盖)

	//Dog子类对象dog
	dog->eat();
	dog->sleep();
	dog->play();//此种方法创建对象Pet *dog = new Dog("小灰灰");再加上基类虚函数的方法:先调用基类play()函数,再调用子类的play()函数
	dog->bark();//这种Dog *dog = new Dog("小灰灰");创建对象方式:可以调用子类的该函数((但是我们明明在Dog子类里对play方法进行了覆盖,但实际上调用的是基类的play方法Pet::play()而不是两个覆盖的子类中的play()方法))

	delete cat;
	delete dog;

	return 0;
}

Tips:

  

------Abstract method------

It is actually like an interface (the interface is similar to the printf() function in C to output to the desktop, because we only need to write it in according to the parameter prompts required by this function, and it can output, but it is internal We don't care how to call the graphics card, so printf can be regarded as an interface); when should we implement it? When our subclass inherits it, and then we need to use this interface, we will implement it in detail.

Because there will be different animals below, and the gameplay is also different, so there is no need to implement this method in the base class.

Because it is not implemented in this class, it is an abstract method, and it is only implemented when inherited.

class Pet
{
public:
	Pet(std::string theName);//构造函数
	virtual void eat();//虚函数
	virtual void sleep();//虚函数
	virtual void play()=0;//定义为抽象的方法。下边不用对它进行实现
protected:
	std::string name;
};
class Cat :public Pet
{
public:
	Cat(std::string theName);
	void climb();
	void play();//对基类play的覆盖(在原有的基础上进行覆盖)
};
class Dog :public Pet 
{
public:
	Dog(std::string theName);
	void bark();
	void play();//对基类play的覆盖
};
Pet::Pet(std::string theName)
{
	name = theName;
}
void Pet::eat()
{
	std::cout<<name<<"正在吃东西"<<std::endl;
}
void Pet::sleep()
{
	std::cout << name << "正在睡觉" << std::endl;
}
//void Pet::play()
//{
//	std::cout << name << "正在玩耍" << std::endl;
//}//因为它是一个抽象的方法所以这里不用给他写实现的东西
Cat::Cat(std::string theName):Pet(theName)//Cat的构造器继承Pet的构造器
{
}
void Cat::climb()
{
	std::cout << name << "正在爬树" << std::endl;
}
void Cat::play()
{
	Pet::play();
	std::cout << name << "正在玩球" << std::endl;
}
Dog::Dog(std::string theName):Pet(theName)//Cat的构造器继承Pet的构造器
{
}
void Dog::bark()
{
	std::cout << name << "正在叫" << std::endl;
}
void Dog::play()
{
	Pet::play();
	std::cout << name << "正在追赶那只猪" << std::endl;
}
//下边主函数同上

PS Summary: The abstract method is the method that does not need to be written in the base class, that is, the virtual method=0;

--------Polymorphism-------

class ClxBase
{
  public:
     ClxBase()
      {

      }
     virtual ~ClxBase()
      {

      }
     virtual void dosomething()//虚函数,为了方便下边的覆盖调用
     {
         std::cout<<"Do something in class ClxBase"<<std::endl;
     }

};
class ClxDerived:public ClxBase
{
 public:
    ClxDerived()
      {

      }
    ~ClxDerived()
      {
           std::cout<<"Output from the destructor of class ClxDerived"<<std::endl
      }
    void dosomething()
     {
         std::cout<<"Do something in class ClxDerived"<<std::endl;
     }

};
int main()
{
    ClxBase *pTest=new ClxDerived;//进行一个声明和定义(这里new出来的是一个ClxDerived对象,给了pTest,)(事实上这个对象就是指向子类的)
    pTest->dosomething();//然后pTest指向dosomething
    delete pTest;
    return 0;
}

The destructors are all virtual methods.

#include<string>
#include<iostream>

class ClxBase
{
public:
	ClxBase()
	{

	}
	//virtual ~ClxBase()
	//{

	//}//带virtual的析构函数,下边输出结构会调用子类的析构函数如左下图
    ~ClxBase()
	{

	}//不带virtual的析构函数,下边输出结构不会调用子类的析构函数如右下图(后边ClxDerived子类的析构函数根本就没有被执行到)
	virtual void dosomething()//虚函数,为了方便下边的覆盖调用
	{
		std::cout << "Do something in class ClxBase" << std::endl;
	}

};
class ClxDerived :public ClxBase
{
public:
	ClxDerived()
	{

	}
	~ClxDerived()
	{
		std::cout << "执行了子类的析构函数" << std::endl;
	}
	void dosomething()
	{
		std::cout << "Do something in class ClxDerived" << std::endl;
	}

};
int main()
{
	ClxBase *pTest = new ClxDerived;//进行一个声明和定义(这里new出来的是一个ClxDerived对象,给了pTest,)(事实上这个对象就是指向子类的)
	pTest->dosomething();//然后pTest指向dosomething//(如果基类的析构不带virtual的话,意思就是它调用了这个子类,但是没有对这个子类进行析构,这是非常非常危险的)
	delete pTest;
	return 0;
}

Result display:

  

//(If the destructor of the base class does not have virtual, it means that it called this subclass, but did not destruct the subclass, which is very, very dangerous)

1 Memory leak means that the memory has not been released after the application has been made. 2 The role of virtual methods is to make our compiler smarter.

If we don’t need to write it in the base class at all, we can write it as an abstract function, that is, a pure virtual function = 0. (Why do we use virtual functions in the base class? Automatic will also become a virtual function, so we only use it in the base class to write it)

 

Guess you like

Origin blog.csdn.net/m0_37957160/article/details/108995576