目录
一、多态的概念
多态用通俗的话来说就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
举个栗子:买票
普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票。
二、多态的定义及实现
1.多态的构成条件
首先,多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。
比如Student继承了 Person。Person对象买票全价,Student对象买票半价。
在继承中构成多态有两个条件:
1.必须通过基类的指针和引用调用虚函数
2.被调用的函数必须是虚函数 ,且派生类必须对基类的虚函数进行重写
例:
class Person
{
public:
virtual void BuyTicket()
{
cout << "买票-全价" << endl;
}
};
class Student : public Person
{
public:
virtual void BuyTicket()
{
cout << "买票-半价" << endl;
}
};
// 多态
// 条件1:虚函数的重写 -> 父子类中两个虚函数,三同(函数名、参数、返回)
// 条件2:父类指针或引用去调用虚函数
void Func(Person& p)
{
p.BuyTicket();
}
int main()
{
Person ps;
Student st;
Func(ps);
Func(st);
return 0;
}
2.虚函数
被virtual修饰的类成员函数称为虚函数
class Person
{
public:
virtual void BuyTicket()
{
cout << "买票-全价" << endl;
}
};
3.虚函数的重写
虚函数的重写(或者覆盖):派生类中有一个跟基类完全相同的虚函数(返回类型、函数名、参数列表完全相同),则称子类的虚函数重写了基类的虚函数
class Person
{
public:
virtual void BuyTicket()
{
cout << "买票-全价" << endl;
}
};
class Student : public Person
{
public:
virtual void BuyTicket()
{
cout << "买票-半价" << endl;
}
};
注:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用
虚函数重写的两个特殊:
1.协变(基类与派生类虚函数返回值类型不同)
即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变
class A
{};
class B : public A
{};
class Person
{
public:
virtual A* f()
{
return new A;
}
};
class Student : public Person
{
public:
virtual B* f()
{
return new B;
}
};
2.析构函数的重写(基类与派生类析构函数的名字不同)
如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字, 都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。
虽然函数名不相同, 看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor。
class Person
{
public:
virtual ~Person() { cout << "~Person()" << endl; }
};
class Student : public Person
{
public:
virtual ~Student() { cout << "~Student()" << endl; }
};
// 只有派生类Student的析构函数重写了Person的析构函数,下面的delete对象调用析构函
//数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。
int main()
{
Person* p1 = new Person;
Person* p2 = new Student;
delete p1;
delete p2;
return 0;
}
4.例题理解(超级重要,强烈建议做一下)
class A
{
public:
virtual void func(int val = 1)
{
std::cout << "A->" << val << std::endl;
}
virtual void test() { func(); }
};
class B : public A
{
public:
void func(int val = 0) { std::cout << "B->" << val << std::endl; }
};
int main(int argc, char* argv[])
{
B* p = new B;
p->test();
return 0;
}
A:A->0