day6
五、继承和派生
1.派生一个类
继承方式(默认为私有继承)
特征 | 公有继承 | 保护继承 | 私有继承 |
---|---|---|---|
公有成员 | 公有成员 | 保护成员 | 私有成员 |
保护成员 | 保护成员 | 保护成员 | 私有成员 |
私有成员 | 私有成员 | 只能通过基类接口访问 | 只能通过基类接口访问 |
向上隐式转换 | 是 | 是(但只能在派生类中) | 否 |
inherit.cpp
#include <iostream>
#include <string.h>
/*
派生一个子类,子类继承父类的所有成员和成员函数(默认为私有继承)
公有继承:继承过来的成员 权限不变
父类 子类
public -> public
protected -> protected
private -> 不可见(只能通过基类接口访问)
保护继承:
public -> protected
protected -> protected
private -> 不可见(只能通过基类接口访问)
私有继承:
public -> 不可见(只能通过基类接口访问)
protected -> 不可见(只能通过基类接口访问)
private -> 不可见(只能通过基类接口访问)
*/
using namespace std;
class father{
public:
double money;
char name[12];
char *GetFName(){
return name;
}
protected:
void SetMoney(double m);
private:
int eyes;
};
class son : public father{
public:
char name[12]; //派生类中有基类同名成员时,将会 隐藏 基类同名的成员,也就是既有自己的name,也有基类的name
void GetMoney(){
money = 2000; //公有继承时,在派生类内部, 可以 直接访问基类 公有成员
SetMoney(1000); //公有继承时,在派生类内部, 可以 直接访问基类 受保护成员
//eyes = 2; //公有继承时,在派生类内部,不可以 直接访问基类 私有成员
}
char *GetSName(){
return name;
}
protected:
private:
};
int main()
{
son obj;
obj.money = 1000; //公有继承时,在派生类外部, 可以 通过对象访问 公有成员
//obj.setMoney(2000); //公有继承时,在派生类外部,不可以 通过对象访问 受保护成员
//obj.eyes = 2; //公有继承时,在派生类外部,不可以 通过对象访问 私有成员
strcpy(obj.name, "zhangsan");
strcpy(obj.father::name, "lisi"); //子类和父类有相同成员,可以通过作用域访问符访问父类同名成员
cout << obj.GetSName() << endl;
cout << obj.GetFName() << endl;
}
2.派生类的构造和析构
inherit.cpp
#include <iostream>
/*
1.继承时的构造顺序:
先基类构造,再派生类构造
----------析构顺序:
先派生类析构,再基类析构
2.包含对象成员的派生类的构造顺序:
先基类构造,再对象成员构造,最后派生类构造
----------析构顺序:
先派生类析构,再对象成员析构,最后基类析构
*/
using namespace std;
#define pri() cout<<"line: "<<__LINE__<<" func: "<<__func__<<endl;
class A{
public:
A(){ pri(); }
~A(){ pri(); }
};
class Base{
public:
Base(){ pri(); }
~Base(){ pri(); }
};
class Subclass : public Base{
public:
Subclass(){ pri(); }
~Subclass(){ pri(); }
A a;
};
int main()
{
Subclass obj;
return 0;
}
inherit.cpp
#include <iostream>
/*
1.派生类构造函数参数初始化列表中,隐式调用基类默认无参构造
2.如果基类出现有参构造,必须在派生类的构造函数参数初始化列表中显式调用基类有参构造
3.如果派生类对象成员的构造函数带参数,必须在派生类的构造函数初始化列表中,为对象成员赋初值
*/
using namespace std;
#define pri() cout<<"line: "<<__LINE__<<" func: "<<__func__<<endl;
class A{
public:
A(){ pri(); }
A(int x){ pri(); }
};
class Base{
public:
Base(){ pri(); }
Base(int x):x(x){ pri(); }
~Base(){ pri(); }
private:
int x;
};
class Subclass : public Base{
public:
Subclass(){ pri(); }
Subclass(int x):a(x),Base(x){ pri(); }
~Subclass(){ pri(); }
private:
A a;
};
int main()
{
Subclass obj1;
Subclass obj2(3);
return 0;
}
3.默认向上隐式转换
inherit.cpp
#include <iostream>
using namespace std;
#define pri() cout<<"line: "<<__LINE__<<" func: "<<__func__<<endl;
class Base{
public:
Base(int x):x(x){ }
int GetValue(){
return x;
}
private:
int x;
};
class Subclass : public Base{
public:
Subclass(int x, int y):x(x), Base(y){ }
int GetX(){
return x;
}
private:
int x;
};
int main()
{
Subclass obj(10, 20);
Base B(0);
cout << obj.GetValue() << endl;
cout << B.GetValue() << endl;
#if 1
B = obj; //默认向上隐式转换。将派生类对象赋值给基类对象时,将派生类类型转换成基类类型,
//派生类将会丢弃自身的数据部分,也称为小范围赋值给大范围
cout << B.GetValue() << endl;
#else
obj = B; //向下转换是不被允许的,不允许将大范围赋值给小范围
#endif
return 0;
}
4.多重继承
名字二义性 inherit.cpp
#include <iostream>
using namespace std;
#define pri() cout<<"Line: "<<__LINE__<<endl;
class A{
public:
void prnmsg(){ pri(); }
};
class B{
public:
void prnmsg(){ pri(); }
};
class C:public A, public B{
public:
};
int main()
{
C obj;
//obj.prnmsg(); //多重继承的名字二义性,解决办法:作用域访问符
obj.A::prnmsg();
obj.B::prnmsg();
return 0;
}
路径二义性 inherite.cpp
#include <iostream>
using namespace std;
#define pri() cout<<"Line: "<<__LINE__<<endl;
class Base{
public:
void prnmsg(){ pri(); }
};
class A:public Base{
public:
};
class B:public Base{
public:
};
class C:public A, public B{
public:
};
int main()
{
C obj;
//obj.prnmsg(); //多重继承的路径二义性,解决方法:作用域访问符或者
//虚基类(虚继承(继承时有virtual关键字修饰)共同的基类)
obj.A::prnmsg();
obj.B::prnmsg();
return 0;
}