

解决数据冗余和二义性用的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即是父也是子,此时可以多态,所以说多态的条件:基类或者是父类这个指针是具有相对性的。