1 继承
代码重用
class Human{
public:
void say(){
cout << "打招呼" << endl;
}
};
//男人
class Man :public Human{
};
void main(){
Man m;
m.say();
//1 父类类型的引用或指针
Human* h_p = &m;
h_p->say();
Human &h1 = m; //和Human h1 = m:不同的是 m和h1指向同一块内存
system("pause");
}
继承的方式就是Man : public Human
打印结果
打招呼
打招呼
可见 Human的子类Man也可以调用父类的方法。
2 向父类构造方法传参
class Human{
public:
Human(char *name,int age){
this->name = name;
this->age = age;
}
void say(){
cout << "打招呼" << endl;
}
protected:
char *name;
int age;
};
//==================男人
class Man : public Human {
public:
Man(char *brother,char* s_name,int s_age,char *h_name,int h_age):Human(s_name,s_age),h(h_name,h_age){
this->brother = brother;
}
void beFather(){
cout << "当爸爸" << endl;
}
private:
char* brother;
Human h;
};
void main(){
Man m("Rose","DeBang",23,"James",31);
system("pause");
}
可见,向父类构造方法传参,可以通过这中方式:
Man(char *brother,char* s_name,int s_age,char *h_name,int h_age):Human(s_name,s_age),h(h_name,h_age)
第二个h表示给成员变量赋值
h(h_name,h_age)
3 父类与子类的构造函数和析构函数的调用顺序
class Hum a n {
public:
Human(){
cout << "Human 构造函数" << endl;
}
~Human(){
cout << "Huamn 析构函数" << endl;
}
};
class Man :public Human{
public:
Man(): Human(){
cout << "Man 构造函数" << endl;
}
~Man(){
cout << "Man 析构函数" << endl;
}
};
void func(){
Man m;
}
void main(){
func();
system("pause");
}
打印结果:
Human 构造函数
Man 构造函数
Man 析构函数
Huamn 析构函数
由此可见,父类的构造函数先调用,子类的析构函数先调用。
4 子类调用父类的方法和属性
class Human{
public:
void method(){
cout << "Human 方法" << endl;
}
int age;
};
class Man:public Human{
public:
void method(){
cout << "Man 方法" << endl;
}
};
void main(){
Man m;
//子类覆盖了和父类重名的方法 此方法将会执行子类中的方法
m.method();
//调用父类的方法
m.Human::method();
//访问父类的属性
m.Human::age;
system("pause");
}
打印结果
Man 方法
Human 方法
5 多继承
//人
class Human{
};
//动物
class Animal{
};
//学生 既是人 又是动物
class Student :public Human, public Animal{
};
6 继承的访问修饰
基类中 继承方式 子类中
public & public继承 public
public & protected继承 protected
public & private继承 private
protected & public继承 protected
protected & protected继承 protected
protected & private继承 private
private & public继承 子类无权访问
private & protected继承 子类无权访问
private & private继承 子类无权访问
比如父类中的age是public修饰的,但是Man使用private继承。所以不能在main中访问Man的age属性
class Human{
public:
int age;
};
class Man :private Human{
};
void main(){
Man m;
m.age;
}
报错:
7 继承的二义性
当A1和A2同时继承了A以后,B同时继承了A1和A2;那么此时B访问继承自A1和A2中的属性将会不明确。即:不知道B访问的是来自A1中的属性还是A2中的属性。如下:
class A{
public:
char* name;
};
class A1 :public A{
};
class A2 :public A{
};
class B :public A1, public A2{
};
void main(){
B b;
b.name = "Green";
}
main函数中将会报错
添加virtual关键字后,将不再出现此问题
class A1 :virtual public A{
};
class A2 :virtual public A{
};
void main(){
B b;
b.name = "Green";
//指定父类 显式调用
b.A1::name;
}
virtual:虚继承,不同路径继承来的同名成员只有一份拷贝,解决不明确的问题。
8 纯虚函数
1 当 一个类有纯虚函数,这个类就是抽象类
//抽象形状
class Shape{
public:
//纯虚函数
virtual void Area() =0;
void print(){
cout << "" << endl;
}
};
//圆
class Circle{
public:
Circle(int r){
this->r = r;
}
void Area(){
cout << "圆的面积" << 3.14*r*r << endl;
}
private:
int r;
};
void main(){
Circle c(10);
c.Area();
system("pause");
}
打印结果
圆的面积314
当圆中不实现Area方法时:
//圆
class Circle{
public:
Circle(int r){
this->r = r;
}
private:
int r;
};
main中调用Area()方法将会报错
2 所以子类继承,必须实现纯虚函数,如果没有实现,则子类也是抽象类。
3 抽象类不能实例化对象
9 接口
接口只是在逻辑上的划分,语法上和抽象类并没有区别
10 模板函数 当两个函数业务逻辑一样,只是参数的数据类型不一样时:
void myswap(int &a,int &b){
int tmp = 0;
tmp = a;
a = b;
b = tmp;
}
void myswap(char&a,char &b){
char tmp = 0;
tmp = a;
a = b;
b = tmp;
}
可以看到这两个函数都是把传来的值交换,只是第一个把两个int类型的值交换,第二个方法是把两个char类型的值交换。这是可以用模板函数:
template<typename T>
void myswap(T& a,T& b){
T tmp = 0;
tmp = a;
a = b;
b = tmp;
}
模板函数和java中的反省如出一辙。
void main(){
//根据实际类型,自动推导
int a = 10, b = 20;
myswap<int>(a,b);
cout << a << "," << b << endl;
char x = 'x', y = 'y';
myswap(x,y);
cout << x << ','<<y << endl;
system("pause");
}
打印结果
20,10
y,x