面向对象程序设计重要概念之一就是多态性
同一个名字定义若干个功能相近的函数 同样的消息被不同对象接受 导致不同的行为 又称为 同一接口 多种方法 即使操作功能有区别 仍可以用同样的接口访问
多态性分为两类 编译时多态行 和运行时多态性 操作符重载 函数重载 就是编译时多态 通过派生类和虚函数实现的多态 是运行时多态 核心虚函数 纯虚函数 抽象类的概念
虚函数
概念 编译时的多态是通过静态联编 实现的 运行时的多态性则是通过动态联编实现的 动态联编核心是虚函数
虚函数是一种在基类中定义为 virtual 的函数 并在一个或多个派生类中再定义的函数 虚函数的特点是 只要定义一个基类的指针 就可以指向派生类的对象 当使用指向派生类对象的基类指针对函数访问时 c++就根据运行时指针所指向的对象去确定调用哪一个函数
在基类成员函数名前面加上 virtual 关键字就说明这个成员函数是虚函数 而虚函数在派生类里再定时 就不必再加关键字virtual了 其一般形式
class 基类名
{
virtual 函数名 (参数表);
};
只有类的成员函数才能声明为虚函数 (类的构造函数 不能声明为 虚函数 )当一个类的成员声明为虚函数 后 该函数在派生类中可能有 不同实现 因此虚函数需要在派生类中需要定义 虚函数可以在多个派生类中重新定义 但函数原型必须完全相同
#pragma warning(disable:4996)
#include
#include //ctrl+shift+f 选中所有相同的单词(代码)替换
using namespace std;
//class sha {//静态联编
//public:
// void d() { cout << "sha" << endl; }
// void f() { d(); }
//};
//class ci :public sha {
//public:
// void draw() { cout << "ci" << endl; }
//};
//void main() {
// ci oneshape;
// oneshape.f();//这个f就是 sha::f { }
//}
class Base
{
public:
Base();
~Base();
virtual void who()
{
cout << "base miao\n";
}
private:
};
class deriv_1: public Base
{
public:
deriv_1();
~deriv_1();
void who()
{
cout << " deriv1 \n" ;
}
private:
};
class deriv_2 :public Base
{
public :
void who()
{
cout << " deriv2 \n";
}
};
deriv_1::deriv_1()
{
}
deriv_1::~deriv_1()
{
}
Base::Base()
{
}
Base::~Base()
{
}
int main()
{
Base base_obj;
Base* b_ptr;
deriv_1 d1_obj;
deriv_2 d2_obj;
b_ptr=&base_obj;
b_ptr->who();
b_ptr = &d1_obj;
b_ptr->who();
b_ptr = &d2_obj;
b_ptr->who();
return 0;
}
使用虚函数 实现运行时多态 的关键在于必须通过基类指针访问 这戏函数
在派生类 中在定义虚函数 是一种特殊的函数重载 他不铜须通常所说的函数重载
这是因为
虚函数的原型必须匹配 在一般 函数重载中 函数的返回类型 和参数的数目都可以 不同 但重载虚函数时 这些都必须是固定不变的
第二虚函数必须定义为类的成员函数 不能定义为友元函数 但可以是其他函数的友元
第三 析构函数可以是虚函数 但构造函数不能是 虚函数
由于重载 一般函数和虚函数不同 把虚函数的定义称为过载 而不叫重载
一旦一个 函数定义为虚函数 无论它向下穿多少层一直保持为虚函数
如果在派生类中没有过载虚函数 则在调用它时 使用基类中定义的函数版本
虚函数的应用
#pragma warning(disable:4996)
#include //c++中结构体与类 的区别是 类的继承私有的默认数据类型是私有的 而结构体是公有的 ,,类里面的变量叫做成员 结构体叫做数据 结构体还是一种数据结构的实现体 类是一个对象的实现体
#include //ctrl+shift+f 选中所有相同的单词(代码)替换
using namespace std;
//class sha {//静态联编 //
//public:
// void d() { cout << "sha" << endl; }
// void f() { d(); }
//};
//class ci :public sha {
//public:
// void draw() { cout << "ci" << endl; }
//};
//void main() {
// ci oneshape;
// oneshape.f();//这个f就是 sha::f { }
//}
class Base
{
public:
Base();
~Base();
virtual void who()
{
cout << "base miao\n";
}
private:
};
class deriv_1: public Base
{
public:
deriv_1();
~deriv_1();
void who()
{
cout << " deriv1 \n" ;
}
private:
};
class deriv_2 :public Base
{
public :
void who()//返回类型要一样或协变 参数个数 类型要一致 而且
{
cout << " deriv2 \n";
}
};
deriv_1::deriv_1()
{
}
deriv_1::~deriv_1()
{
}
Base::Base()
{
}
Base::~Base()
{
}
//int main()
//{
// Base base_obj;
// Base* b_ptr;
// deriv_1 d1_obj;
// deriv_2 d2_obj;
// b_ptr=&base_obj;
// b_ptr->who();
// b_ptr = &d1_obj;
// b_ptr->who();
// b_ptr = &d2_obj;
// b_ptr->who();
//
// return 0;
//}
class figure
{
public:
figure();
~figure();
void set_dim(double i, double j=0)
{
x = i; y = j; r = i;
}
virtual void show_area()
{
cout << " no area computation(计算) defined" ;
cout <<"\n" ;
}
protected:
double x, y,r;
};
class triangle:public figure
{
public:
triangle();
~triangle();
void show_area()
{
cout << "height*0.5*base :" << x * y * 0.5 << "\n";
}
private:
};
class rectangle:public figure
{
public:
rectangle();
~rectangle();
void show_area()
{
cout << "height*width :" << x * y * 0.5 << "\n";
}
private:
};
class circle:public figure
{
public:
circle();
~circle();
void show_area()
{
cout << 3.1415926 * r * r;
}
private:
};
circle::circle()
{
}
circle::~circle()
{
}
rectangle::rectangle()
{
}
rectangle::~rectangle()
{
}
triangle::triangle()
{
}
triangle::~triangle()
{
}
figure::figure()
{
}
figure::~figure()
{
}
int main()
{
figure* p;
triangle t;
rectangle r;
circle c;
p = &t;
p->set_dim(10.0, 5.0);
p->show_area();
p = &r;
p->set_dim(10.0, 5.0);
p->show_area();
p = &c;
p->set_dim(10.0);
p->show_area();
return 0;
}
一般情况下 可将各层次类中的共性成员定义为虚函数 某个类特有成员 没有必要说明为虚函数
纯虚函数和抽象基类
当派生类 中 未过载函数而被派生类调用时 就使用它的积累定义的函数坂本 但在许多情况下 积累定义的虚函数并没有实际意义 应有一定的方法保证 派生类确实定义了自己所必需的虚函数 引入纯虚函数 在 c++中 把含有一个或多个纯虚函数 的类叫做抽象类
纯虚函数
纯虚函数是定义在基类中的一种函数
在即类定义中值给函数的原型 没有任何与该基类有关的定义 这样的函数 就叫做纯虚函数 纯虚函数的存在 使得任何派生类 都必须定义自己的函数版本
不然编译都不能通过
一般形式
virtual type func_name(parameter_list)=0;//参数 parameter
type 是函数返回类型
声明为纯虚函数的基类 只是用于继承 仅作为一个接口 具体功能 体现在派生类中
抽象基类
含有纯虚函数的基类叫做抽象基类
抽象基类有一个重要特性 即抽象类 不能建立对象 抽象基类只能用作 其它类继承的基类
抽象基类可以有自己的指针 以支持运行时的多态性
编译连接 和 执行连接
在面向对象程序设计中 两个术语 先连接 和 后连接 先连接系指编译时进行的连接
后连接 指运行程序时才进行连接也称执行连接
在面向对象方法的术语中 编译时连接意味着编译源程序时就将对象和函数调用连接起来 叫用函数所需的全部信息在编译程序时就知道
标准函数的调用 重载函数的调用 重载操作符的调用
先连接的优点 执行速度快 缺点是灵活性差
后连接意味着在运行对象才同其函数连接起来 执行链接在c++中是通过虚函数和派生类实现的
后来你姐的有点事他有较大的灵活性 可用于支持各种对象使用统一接口和
各自功能实现 缺点 运行速度稍微慢一点
大多数程序都是二者同时使用
#pragma warning(disable:4996)
#include //c++中结构体与类 的区别是 类的继承私有的默认数据类型是私有的 而结构体是公有的 ,,类里面的变量叫做成员 结构体叫做数据 结构体还是一种数据结构的实现体 类是一个对象的实现体
#include //ctrl+shift+f 选中所有相同的单词(代码)替换
#include
using namespace std;
//class sha {//静态联编 //
//public:
// void d() { cout << "sha" << endl; }
// void f() { d(); }
//};
//class ci :public sha {
//public:
// void draw() { cout << "ci" << endl; }
//};
//void main() {
// ci oneshape;
// oneshape.f();//这个f就是 sha::f { }
//}
class Base
{
public:
Base();
~Base();
virtual void who()
{
cout << "base miao\n";
}
private:
};
class deriv_1: public Base
{
public:
deriv_1();
~deriv_1();
void who()
{
cout << " deriv1 \n" ;
}
private:
};
class deriv_2 :public Base
{
public :
void who()//返回类型要一样或协变 参数个数 类型要一致 而且
{
cout << " deriv2 \n";
}
};
deriv_1::deriv_1()
{
}
deriv_1::~deriv_1()
{
}
Base::Base()
{
}
Base::~Base()
{
}
//int main()
//{
// Base base_obj;
// Base* b_ptr;
// deriv_1 d1_obj;
// deriv_2 d2_obj;
// b_ptr=&base_obj;
// b_ptr->who();
// b_ptr = &d1_obj;
// b_ptr->who();
// b_ptr = &d2_obj;
// b_ptr->who();
//
// return 0;
//}
class figure
{
public:
figure();
~figure();
void set_dim(double i, double j=0)
{
x = i; y = j; r = i;
}
virtual void show_area() = 0;
protected:
double x, y,r;
};
class triangle:public figure
{
public:
triangle();
~triangle();
void show_area()
{
cout << "height*0.5*base :" << x * y * 0.5 << "\n";
}
private:
};
class rectangle:public figure
{
public:
rectangle();
~rectangle();
void show_area()
{
cout << "height*width :" << x * y * 0.5 << "\n";
}
private:
};
class circle:public figure
{
public:
circle();
~circle();
void show_area()
{
cout << 3.1415926 * r * r;
}
private:
};
circle::circle()
{
}
circle::~circle()
{
}
rectangle::rectangle()
{
}
rectangle::~rectangle()
{
}
triangle::triangle()
{
}
triangle::~triangle()
{
}
figure::figure()
{
}
figure::~figure()
{
}
//纯虚函数
class functions
{
public:
functions();
~functions();
functions(float f) { val = f; }
//virtual void output() {}//这个就不是纯虚函数
virtual void output() = 0;
protected:
float val;
};
class func_sin:public functions
{
public:
func_sin();
~func_sin();
func_sin(float f) :functions(f)
{
}
void output()
{
cout << sin(val) << endl;
}
private:
};
class func_cos:public functions
{
public:
func_cos();
~func_cos();
func_cos(float f) :functions(f) {}
void output()
{
cout << cos(val)<<endl;
}
private:
};
func_cos::func_cos()
{
}
func_cos::~func_cos()
{
}
func_sin::func_sin()
{
}
func_sin::~func_sin()
{
}
functions::functions()
{
}
functions::~functions()
{
}
int main()
{
func_sin s(0);
s.output();
func_cos c(0);
c.output();
return 0;
}