22.多态(上)

解决数据冗余和二义性用的virtual和这里的virtual没有关系,一语两用。

cpp 复制代码
class Person
{
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
};

class Student : public Person {
public:
	virtual void BuyTicket() { cout << "买票-打折" << endl; }
};
int main()
{
}

你有个虚函数我有个虚函数,这两个还满足三同

感受一下条件,必须是基类的指针和引用,按照继承的角度有个切片和切割,赋值兼容规则,指针或者引用,可以传基类过去或者子类派生类,指向谁调用谁,多态就是多种形态

父类的指针,如果没提多态的概念,我们认为调用的都是父类的buyticket,由调用类型决定的,跟你指向的对象没关系,现在跟类型没关系,指向谁调用谁。

如果把父类的虚函数去掉那就不满足条件2,没有完成虚函数的重写或者覆盖,此时虚函数的重写没完成

满足多态指向谁调用谁,不满足多态,就是跟以前一样,看ptr类型,ptr是父类的就调用父类的

引用也行,如果是基类对象呢,此时也不满足多态,调用的也是父类

子类就不能穿父类。只能穿子类。

cpp 复制代码
class Animal
{
public:
	virtual void talk() const
	{}
};

class Dog : public Animal
{
public:
	virtual void talk() const
	{
		std::cout << "汪汪" << std::endl;
	}
};

class Cat : public Animal
{
public:
	virtual void talk() const
	{
		std::cout << "(>^ω^<)喵" << std::endl;
	}
};
void letsHear(const Animal& animal)
{
	animal.talk();
}
int main()
{


	Cat cat;
	Dog dog;
	letsHear(cat);
	letsHear(dog);

	return 0;
}

多态在不同子类之间 不同对象传一个函数,可以实现多态,animal是父类,穿子类可以实现切片,

只有基类的指针才可以穿不同子类,动物鸭子老虎,2.虚函数重写

B当中的virtual 重写了A中的virtual,B中val改成x也构成,缺省值也不重要。

继承是指搜索规则搜索text现在B里面搜。搜到text隐藏A,搜不到去A搜,继承并不会真的弄下来。所以不管A调用B调用都是A*,所以这里P给A*,父类指针基类指针去调用,如果是B*就不满足,2.虚函数重写,,满足构成多态,这里和A*没有关系了,和指向对象有关,调用B的

然而选B,

重写是重写实现,为什么不加virtual都可以,满足多态以后用父类声明部分加派生类实现,组成重写,重写的本质是重写虚函数。所以可以不加virtual,

这种情况不满足多态,

p不是基类指针是子类指针,不构成多态,

多态才复杂组合,普通没这么多弯弯绕绕。

cpp 复制代码
class A {};
class B : public A {};
//

//协变
class Person {
public:
	virtual A* BuyTicket()
	{
		cout << "买票-全价" << endl;
		return nullptr;
	}
};

class Student : public Person {
public:
	virtual B* BuyTicket()
	{
		cout << "买票-打折" << endl;
		return nullptr;
	}
};

void Func(Person* ptr)
{
	ptr->BuyTicket();
}

int main()
{
	Person ps;
	Student st;

	Func(&ps);
	Func(&st);

	return 0;
}

返回值不同构成协变,满足多态,必须是父类和子类指针和引用这就编译报错

这样也行,只要是父子类就行

cpp 复制代码
class A
{
public:
	virtual ~A()
	{
		cout << "~A()" << endl;
	}
};

class B : public A {
public:
	// 构成重写
	~B()
	{
		cout << "~B()->delete:" << _p << endl;
		delete _p;
	}
protected:
	int* _p = new int[10];
};

int main()
{
	A* p1 = new A;
	A* p2 = new B;

	// p1->destructor() + operator delete 
	delete p1;
	delete p2;

	return 0;
}

我有个父类指针,可能指向父类可能指向子类,delete第一个调用父类的析构函数,第二个期望调用子类析构,因为new的子类对象,如果把这个virtual去掉就不构成多台了

运行崩溃,只掉用到了A的析构,B

没钓到------p就没释放,内存泄漏,这里只能达成多态才能解决问题,就是不是和类型有关,而是和指向对象有关,第一个条件已经满足了,父类的指针或者引用调用,2.虚函数的重写,满足多态,

第一个A,第二个B调用,结束后自动调用父类。

调父类时候调不到

实际不需要现实调,如果我想显示调,加指定

因为子类析构和父类析构,不是多态情况下构成隐藏,因为他们两的函数名是相同的,因为被处理成destruct,因为在这个多态场景。

捋一下:因为析构函数构成多态,资源才能正确释放,所以析构函数名字被处理成destruct,所以派生类的析构函数构成隐藏,

不构成虚函数重写就不构成多态,就存在内存泄漏的风险,所以要把析构函数名称处理成destucter,这样函数名相同,面试很常考

结合这个场景讲,

C++11提供了两个关键字

没有完成重写编译时 报错

derive函数看看这是否完成重写,函数名写错了,派生类后面加上override就可以帮助检查

跟asssert有些类似,assert是运行时的,我这是编译时的

父类加finial不鞥能重写,了解就行。

现实当中没有具体的类别对应那就要定义成抽象类,因为不能实例化对象,

animal就可以定义成抽象类,因为动物没法实例化,继承以后才能,假如要定义一个车,抽象类不能实例化出对象

我们用一个类继承,不重写虚函数,那我也是抽象类

因为我继承了纯虚函数,我不包含,但我也有纯虚函数,我也是抽象类,也无法实例化。重写一下虚函数就可以实例化处对象,因为重写之后就不包含纯虚函数

纯虚函数抽象类某种程度强制子类重写虚函数,

多态就更完整了,父类没有对象,但是父类有指针

父类不能实例化处对象,但是父类指针和引用可以定义,父类这个抽象类的指针指向子类,指向那个子类,调用哪个子类的虚函数

B继承A,那我用B*的指针一定不能实现多态吗,不一定,因为这个B有双重意义,只有A或者B注定无法实现多态,因为B的指针只能指向B你能指向A吗,只有A的指针才能实现多态,

若我再加个D,此时就不一样了,B即是父也是子,此时可以多态,所以说多态的条件:基类或者是父类这个指针是具有相对性的。

相关推荐
666HZ66639 分钟前
C语言——高精度加法
c语言·开发语言·算法
sweet丶1 小时前
iOS MMKV原理整理总结:比UserDefaults快100倍的存储方案是如何炼成的?
算法·架构
星释1 小时前
Rust 练习册 100:音乐音阶生成器
开发语言·后端·rust
D_evil__1 小时前
[C++高频精进] 并发编程:线程基础
c++
风生u2 小时前
go进阶语法
开发语言·后端·golang
666HZ6662 小时前
C语言——黑店
c语言·开发语言
Gomiko2 小时前
JavaScript基础(八):函数
开发语言·javascript·ecmascript
云里雾里!2 小时前
力扣 209. 长度最小的子数组:滑动窗口解法完整解析
数据结构·算法·leetcode
〝七夜5692 小时前
JVM内存结构
java·开发语言·jvm