1.基本概念
多态分为两类
- 静态多态:函数重载和运算符重载属于静态多态,复用函数
- 动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态区别
- 静态多态的函数地址早已绑定——编译阶段确定函数地址
- 动态多态的函数地址晚绑定——运行阶段确定函数地址
动态多态条件
- 继承关系
- 子类和父类有函数重写(即函数同名)
动态多态使用
- 父类的指针或引用 指向子类对象
void dospeak(school &s) //父类的指针或引用指向子类的对象
{
s.index();}
class school
{
public:
//虚函数(父类必加,子类无所谓)
virtual void index()
{
cout << "通知" << endl;
}
};
class teacher :public school
{
public:
void index()
{
cout << "老师转发通知" << endl;
}
};
class student :public school
{
public:
void index()
{
cout << "学生转发通知" << endl;
}
};
void dospeak(school &s) //父类的指针或引用执行子类的对象
{
s.index();//因为此时用的是school类的对象,所以地址早绑定。与传入的对象是哪个子类无关,运行的是父类中的index()函数
}
//如果想传输的哪个子类就运行哪个子类的index函数,必须让函数地址晚绑定,在运行阶段进行
//在父类函数前加virtual
void test()
{
teacher t;
dospeak(t);
student s;
dospeak(s);//根据传输对象再确定地址
}
int main()
{
test();
system("pause");
return 0;
}
2.多态的深入剖析 (不好写,看视频136课)
3.计算器类案例
实现两个操作数相加
普通写法
class school
{
public:
int m_age;
int m_num;
int sum(string oper) //传入符号做判断
{
if (oper == "+")
{
return m_age + m_num;
}
else if (oper == "-")
{
return m_age - m_num;
}
}
};
void test()
{
school s; string oper;
s.m_age = 19; s.m_num = 23;
cout << "请输入加或减符号" << endl;
cin >> oper;
cout << s.sum(oper) << endl;
}
int main()
{
test();
system("pause");
return 0;
}
自己写的。
存在问题:如果用一个新的类添加新的计算功能,在使用虚函数的情况下,必须有新的类建立一个对象,才能使用新功能,且旧的功能也必须用函数所在的类创建一个对象
class calculator
{
public:
int m_age;
int m_num;
virtual int sum(string oper) //传入符号做判断
{
if (oper == "+")
{
return m_age + m_num;
}
else if (oper == "-")
{
return m_age - m_num;
}
}
};
class cal2 :public calculator
{
public:
int sum(string oper)
{
if (oper == "*")
{
return m_age * m_num;
}
}
};
void add(calculator &c,string &oper )
{
c.sum(oper);
}
void test()
{
cal2 c; string oper;
calculator s;
s.m_age = 119; s.m_num = 233;
c.m_age = 19; c.m_num = 23;
cout << "请输入符号" << endl;
cin >> oper;
add(c, oper); add(s, oper);
//cout << c.sum(oper) << endl;
cout << s.sum(oper) << endl; //父类的函数变成虚函数后
//父类,子类建立的对象好像只能也各自调用各自类的函数,不能直接子类调用所有函数。
}
老师答案.
组织性强,拓展性高
虽然各自类也只能调用各自类的函数,但实现起来简单
重点:calculator *c = new add(); //这里父类创建了一个指针,接收了new为add类开辟的一块内存的地址,这块内存相当于add类实例化的一个对象
//因此满足了多态,父类的指针或引用指向子类的对象这个条件
又因为父类的函数是虚函数,则各个计算函数的调用,c->getresult()由实例化的类的类型决定。
子类的virtual不是必须,可写可不写
class calculator
{
public:
int m_num1;
int m_num2;
virtual int getresult()
{
return 0;
}
};
//加法计算器类
class add :public calculator
{
public:
virtual int getresult()
{
return m_num1 + m_num2;
}
};
class sub :public calculator
{
public:
virtual int getresult()
{
return m_num1 - m_num2;
}
};
class mul :public calculator
{
public:
virtual int getresult()
{
return m_num1 * m_num2;
}
};
void test()
{
calculator *c = new add(); //这里父类创建了一个指针,接收了new为add类开辟的一块内存的地址,这块内存相当于add类实例化的一个对象
//因此满足了多态父类的指针或引用指向子类的对象这个条件
c->m_num1 = 10; c->m_num2 = 20;
cout << c->getresult() << endl; //也是只能用一次
delete c; //记得销毁
c = new sub(); //这里只是销毁了内存数据,c还是个指针。new 类型后记得加()
c->m_num1 = 10; c->m_num2 = 20;
cout << c->getresult() << endl; //也是只能用一次
delete c;
}
int main()
{
test();
system("pause");
return 0;
}