#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
//什么是多态:
//有多个完全不同的对象,对它们发送同一个消息,它们反应各不相同,分别执行不同的操作。这种情况就是多态现象
//例:甲乙丙3个班都是高二年级,他们有基本相同的属性和行为,但在听到上课铃声时,他们却是走向3个不同班级
//c++中所谓的多态是指:
//由继承产生的相关的但不同的类,其对象对同一消息会作出不同的响应
class Parent
{
public:
Parent(string name)
{
this->name = name;
}
//说明父类的这个函数为虚函数
virtual void func()
{
cout << "parent func()......" << endl;
cout << "this->name:" << this->name << endl;
}
private:
string name;
};
class Child :public Parent
{
public:
Child(string name) :Parent("father")
{
this->name = name;
}
//当父类中的一个虚函数在子类中被重写,那么执行赋值兼容原则的方法时,便不会去执行父类的方法了,而是去执行被子类重写的方法,这就形成了c++的多态
//注意:只有子类重定义父类的虚函数时,才叫重写,其他的就直接叫重定义
virtual void func()//当子类里重写了父类的虚函数时,通常在子类重写的方法前也加上virtual,代表子类中这个函数为重写父类虚函数,提高代码的可读性,但对编译器是没有任何影响的
{
cout << "child func()......" << endl;
cout << "this->name:" << this->name << endl;
}
private:
string name;
};
//全局方法,多态的前提的赋值兼容原则,大的可以给小的赋值
//void print(Parent p)当传入的是父类对象时,不会发生多态,尽管子类重写了父类的虚函数,因为传入对象时,这时是重新创建了一个父类对象p,这个父类对象p和传入进来的子类和父类没有任何关系,你调用p类的方法,它当然是执行p对象的方法
//总结:发生多态的三个必要条件
//1.要有继承
//2.子类要有父类的虚函数重写
//3.全局方法中传入的是父类对象的指针或引用,不能是父类的对象,即要存在父类的指针或引用指向子类对象
class Animal
{
public://类中不写权限关键字,默认为私有成员变量
virtual void roar()
{
cout << "animal roar..." << endl;
}
};
class Dog :public Animal
{
public:
virtual void roar()
{
cout << "dog wangwangwang..." << endl;
}
};
class People
{
public:
void say()
{
cout << "people bbb..." << endl;
}
};
void print(Parent &p)
{
p.func();
}
void roar(People &p, Animal &a)
{
p.say();
a.roar();//这儿发生了多态
}
class A
{
public:
A()
{
this->p = new char[64];
memset(this->p, 0, 64);
strcpy(this->p, "A string...");//strcpy函数会拷贝一个\0
}
virtual void print()
{
cout << this->p << endl;
}
virtual ~A()
{
if (this->p != NULL)
{
delete[] p;
}
cout << "~A()......" << endl;
}
private:
char *p;
};
class B :public A
{
public:
B()
{
this->p = new char[64];
memset(this->p, 0, 64);
strcpy(this->p, "B string...");
}
virtual void print()
{
cout << this->p << endl;
}
virtual ~B()
{
if (this->p != NULL)
{
delete[] p;
}
cout << "~B()......" << endl;//子类中创建时会调用父类的构造函数,删除时也会调用父类的析构函数
}
private:
char *p;
};
void test1(A &a)//因此传进来的引用在栈区,因此父类A和子类B的析构函数都是自动触发,不需要我们手动回收空间
{
a.print();//这儿发生了多态
}
void test2(A *a)//因为传进来的指针指向的对象在堆空间,因此堆空间对象的析构函数不会自动触发,需要手动释放
{
a->print();//这儿发生了多态
delete a;//这儿如果你不把父类的析构函数改为虚析构函数,那么这儿删除堆空间触发的是父类的析构函数,并不是子类的析构函数,因此这儿也需要发生多态,即把父类的析构函数写成虚析构函数,出发了子类的析构函数就会关联触发父类的析构函数,这样就不会发生内存泄漏了
}
class C
{
public:
virtual ~C()
{
cout << "~C()......" << endl;
}
};
class D :public C
{
public:
//当子类对象在堆空间时,回收空间时需要发生多态,这时需要使父类的析构函数变为虚析构函数
//当子类对象在栈空间时,不需要考虑这些
virtual ~D()
{
cout << "~D()......" << endl;
}
};
void test3(C *c)
{
delete c;//发生了多态
}
int main()
{
Parent p1("parent");
Child c1("child");
//下面一段代码虽然传入参数为子类对象,但输出的结果为父类函数输出的结果
//原因:编译器默认做了一个安全处理。编译器认为不管传递是子类对象还是父类对象,如果统一执行父类的方法则一定成功,所以这儿编译器就调用了父类的方法
//总结:因此不论传入的是子类对象还是父类对象,使用赋值兼容性原则调用全局函数,执行的一定是父类的方法
//如何使传入的是子类对象就执行子类对象方法,传入的是父类的对象就执行父类对象的方法?
//引入虚函数,即在父类的方法前加virtual关键字,虚函数关键字虽然和虚继承关键字一样,但完全是两个意思,它们两没有任何关系
print(p1);
print(c1);
People p2;
Dog d2;
roar(p2, d2);
//联编是指代码相互关联的过程,属于编译器的知识
//1.静态联编:是程序的匹配、连接在编译阶段实现,也成为早起联编。重载函数使用静态联编
//2.动态联编:指程序联编推迟到运行时进行,又称为晚期联编。switch语句和if语句使用动态联编,多态对于编译器来讲也是一个动态联编
B b1;
test1(b1);
B *b2 = new B;
test2(b2);
cout << endl << endl;
D *d = new D;
test3(d);
//重载,重写,重定义
//1.重载:一定是同一个作用域下,函数名相同,函数参数类型或个数不同
//2.重定义:一定发生在继承时的父子类中,子类重定义了父类的函数,函数名和参数返回值完全相同,只是函数体不同
//3.重写:重写是一种特殊情况的重定义,子类重定义的函数为父类的虚函数时,即被称为重写,重写只有虚函数有关,重写是发生多态的必要条件
return 0;
}
#include <iostream>
#include <string>
using namespace std;
//什么是多态:
//有多个完全不同的对象,对它们发送同一个消息,它们反应各不相同,分别执行不同的操作。这种情况就是多态现象
//例:甲乙丙3个班都是高二年级,他们有基本相同的属性和行为,但在听到上课铃声时,他们却是走向3个不同班级
//c++中所谓的多态是指:
//由继承产生的相关的但不同的类,其对象对同一消息会作出不同的响应
class Parent
{
public:
Parent(string name)
{
this->name = name;
}
//说明父类的这个函数为虚函数
virtual void func()
{
cout << "parent func()......" << endl;
cout << "this->name:" << this->name << endl;
}
private:
string name;
};
class Child :public Parent
{
public:
Child(string name) :Parent("father")
{
this->name = name;
}
//当父类中的一个虚函数在子类中被重写,那么执行赋值兼容原则的方法时,便不会去执行父类的方法了,而是去执行被子类重写的方法,这就形成了c++的多态
//注意:只有子类重定义父类的虚函数时,才叫重写,其他的就直接叫重定义
virtual void func()//当子类里重写了父类的虚函数时,通常在子类重写的方法前也加上virtual,代表子类中这个函数为重写父类虚函数,提高代码的可读性,但对编译器是没有任何影响的
{
cout << "child func()......" << endl;
cout << "this->name:" << this->name << endl;
}
private:
string name;
};
//全局方法,多态的前提的赋值兼容原则,大的可以给小的赋值
//void print(Parent p)当传入的是父类对象时,不会发生多态,尽管子类重写了父类的虚函数,因为传入对象时,这时是重新创建了一个父类对象p,这个父类对象p和传入进来的子类和父类没有任何关系,你调用p类的方法,它当然是执行p对象的方法
//总结:发生多态的三个必要条件
//1.要有继承
//2.子类要有父类的虚函数重写
//3.全局方法中传入的是父类对象的指针或引用,不能是父类的对象,即要存在父类的指针或引用指向子类对象
class Animal
{
public://类中不写权限关键字,默认为私有成员变量
virtual void roar()
{
cout << "animal roar..." << endl;
}
};
class Dog :public Animal
{
public:
virtual void roar()
{
cout << "dog wangwangwang..." << endl;
}
};
class People
{
public:
void say()
{
cout << "people bbb..." << endl;
}
};
void print(Parent &p)
{
p.func();
}
void roar(People &p, Animal &a)
{
p.say();
a.roar();//这儿发生了多态
}
class A
{
public:
A()
{
this->p = new char[64];
memset(this->p, 0, 64);
strcpy(this->p, "A string...");//strcpy函数会拷贝一个\0
}
virtual void print()
{
cout << this->p << endl;
}
virtual ~A()
{
if (this->p != NULL)
{
delete[] p;
}
cout << "~A()......" << endl;
}
private:
char *p;
};
class B :public A
{
public:
B()
{
this->p = new char[64];
memset(this->p, 0, 64);
strcpy(this->p, "B string...");
}
virtual void print()
{
cout << this->p << endl;
}
virtual ~B()
{
if (this->p != NULL)
{
delete[] p;
}
cout << "~B()......" << endl;//子类中创建时会调用父类的构造函数,删除时也会调用父类的析构函数
}
private:
char *p;
};
void test1(A &a)//因此传进来的引用在栈区,因此父类A和子类B的析构函数都是自动触发,不需要我们手动回收空间
{
a.print();//这儿发生了多态
}
void test2(A *a)//因为传进来的指针指向的对象在堆空间,因此堆空间对象的析构函数不会自动触发,需要手动释放
{
a->print();//这儿发生了多态
delete a;//这儿如果你不把父类的析构函数改为虚析构函数,那么这儿删除堆空间触发的是父类的析构函数,并不是子类的析构函数,因此这儿也需要发生多态,即把父类的析构函数写成虚析构函数,出发了子类的析构函数就会关联触发父类的析构函数,这样就不会发生内存泄漏了
}
class C
{
public:
virtual ~C()
{
cout << "~C()......" << endl;
}
};
class D :public C
{
public:
//当子类对象在堆空间时,回收空间时需要发生多态,这时需要使父类的析构函数变为虚析构函数
//当子类对象在栈空间时,不需要考虑这些
virtual ~D()
{
cout << "~D()......" << endl;
}
};
void test3(C *c)
{
delete c;//发生了多态
}
int main()
{
Parent p1("parent");
Child c1("child");
//下面一段代码虽然传入参数为子类对象,但输出的结果为父类函数输出的结果
//原因:编译器默认做了一个安全处理。编译器认为不管传递是子类对象还是父类对象,如果统一执行父类的方法则一定成功,所以这儿编译器就调用了父类的方法
//总结:因此不论传入的是子类对象还是父类对象,使用赋值兼容性原则调用全局函数,执行的一定是父类的方法
//如何使传入的是子类对象就执行子类对象方法,传入的是父类的对象就执行父类对象的方法?
//引入虚函数,即在父类的方法前加virtual关键字,虚函数关键字虽然和虚继承关键字一样,但完全是两个意思,它们两没有任何关系
print(p1);
print(c1);
People p2;
Dog d2;
roar(p2, d2);
//联编是指代码相互关联的过程,属于编译器的知识
//1.静态联编:是程序的匹配、连接在编译阶段实现,也成为早起联编。重载函数使用静态联编
//2.动态联编:指程序联编推迟到运行时进行,又称为晚期联编。switch语句和if语句使用动态联编,多态对于编译器来讲也是一个动态联编
B b1;
test1(b1);
B *b2 = new B;
test2(b2);
cout << endl << endl;
D *d = new D;
test3(d);
//重载,重写,重定义
//1.重载:一定是同一个作用域下,函数名相同,函数参数类型或个数不同
//2.重定义:一定发生在继承时的父子类中,子类重定义了父类的函数,函数名和参数返回值完全相同,只是函数体不同
//3.重写:重写是一种特殊情况的重定义,子类重定义的函数为父类的虚函数时,即被称为重写,重写只有虚函数有关,重写是发生多态的必要条件
return 0;
}