继承语法
class 子类名:继承方式1 基类1,继承方式2 基类2…{
…
};
公有继承:public
保护继承:protected
私有继承:private
继承方式 | 基类public成员 | 基类protected成员 | 基类private成员 |
---|---|---|---|
public | public | protected | private |
protected | protected | protected | private |
private | private | private | private |
这张表格里面公有继承,基类的访问控制权限不变; 保护继承,基类的访问控制权限最低为protected; 私有继承,基类的访问控制权限全部为private.
访问控制限定符 | 访问控制属性 | 基类 | 子类 | 外部 | 友元 |
---|---|---|---|---|---|
public | 公有成员 | OK | OK | OK | OK |
protected | 保护成员 | OK | OK | NO | OK |
private | 私有成员 | OK | NO | NO | OK |
#include <string>
#include <iostream>
using namespace std;
class Human
{
public:
Human()
{
cout << "Human 构造:" << this << endl;
}
void sleep(){
cout << "基类 Sleep" << endl;
}
private:
int m_age;
protected:
string m_name;
public:
bool m_gender; //0 女 1 男
int m_show;
}; //基类 父类
class Student : public Human
{
public:
Student() : m_id(0)
{
/*
* 1.派生类可以直接访问基类的所有公有和保护成员,其效果如同它们是在派生类中声明一样
*/
//基类中的保护成员在派生类中可以访问
m_name = "梦凡";
//基类中的公有成员在派生类中可以访问
m_gender = 1;
/*
* 2.对于基类的私有成员,在派生类中存在但不能访问
*/
//m_age = 10;
}
void show()
{
//隐藏基类中的m_show变量 基类中的m_show存在,用作用域限定符访问
cout << "派生类中的 m_show:" << m_show <<" "<< "基类中的m_show:" << Human::m_show << endl;
}
private:
int m_id;
public:
// 3.同名隐藏 派生类中定义基类中同名的公有成员或保护成员(成员包括成员变量和成员函数)
int m_show; //隐藏基类中的m_show变量 基类中的m_show存在,用作用域限定符访问
int sleep; //隐藏基类中的sleep()函数
}; //派生类 子类
int main()
{
Student s;
/*
* 3.同名隐藏测试
*/
//s.sleep("水果"); //会报错 因为派生类中的sleep变量将父类中的sleep函数隐藏了
s.m_show = 10; //m_show为派生类中的m_show
s.Human::m_show = 20; //通过作用域访问基类中的m_show
s.show();
/*
* 4.公有继承 派生类对象任何时候都可以被当成基类类型对象
* 基类对象不能隐式转换成派生类对象
*/
//缩小访问范围 安全
Human h = s;
h.sleep(); //不报错,因为派生类对象隐式转换成基类对象
Human* ph = &s; //基类指针指向派生类对象 ph隐式指向基类部分
Human& rh = s; //基类引用指向派生类对象 rh隐式指向基类部分
cin.get();
return 0;
}
将基类构造函数设为私有,子类永远无法被实例化对象,实现阻断继承
//阻断继承 将构造函数声明为私有
class parent
{
private:
parent() {}
};
class son :public parent
{
};
int main()
{
//son s; 无法实例化对象
}
#include <string>
#include <iostream>
using namespace std;
class Human
{
public:
Human()
{
cout << "Human构造 this:" << this << endl;
}
Human(int age)
{
cout << "Human单参 this:" << this << endl;
}
private:
int m_age;
string m_name;
int m_gender;
}; //基类
class Student : public Human
{
public:
//默认调用基类无参构造
//Student() :m_no(0) {
// cout << "Student构造 this:" << this << endl;
//}
/*
* 2.通过初始化列表选择基类的构造方式
*/
Student(int age) :Human(age), m_no(0)
{
std::cout << "Student单参构造 this:" << this << std::endl;
}
private:
int m_no;
};
int main()
{
/*
* 1.构造顺序 在构造析构里面分析过
* 为整个对象分配内存
* 构造基类部分(如果存在基类)
* 构造成员变量
* 执行构造函数代码
*/
//无参构造
//Student s1;
//单参构造
Student s1(18);
cin.get();
return 0;
}
一个类可以从多个基类继承
子类对象中的基类子对象按照继承表顺序依次构造
#include <iostream>
using namespace std;
class Telephone
{
public:
Telephone()
{
cout << "Telephone构造" << endl;
}
void call()
{
cout << "打电话" << endl;
}
int m_t;
};
class Camera
{
public:
Camera()
{
cout << "Camera构造" << endl;
}
void photo()
{
cout << "照相" << endl;
}
int m_c;
};
class Ipod
{
public:
Ipod()
{
cout << "Ipod构造" << endl;
}
void music()
{
cout << "听歌" << endl;
}
int m_i;
};
//子类对象中的基类子对象按照继承表顺序依次构造
class IphoneXs :public Telephone, public Camera, public Ipod
{
public:
IphoneXs()
{
cout << "IphoneXs构造" << endl;
}
int i;
};
int main()
{
IphoneXs ipx; //构造一个子类对象
ipx.call();
ipx.photo();
ipx.music();
cout << "------------------" << endl;
//基类指针指向子类对象
Telephone* t = &ipx; //公有继承 皆然性 子类IS A父类
Camera* c = &ipx; //公有继承 皆然性 子类IS A父类
Ipod* i = &ipx; //公有继承 皆然性 子类IS A父类
cout << t << " " << c << " " << i << endl;
cin.get();
return 0;
}
Telephone构造
Camera构造
Ipod构造
IphoneXs构造
打电话
照相
听歌
------------------
006FF754 006FF758 006FF75C
中间子类有公共基类,导致最终子类存在多个公共基类,导致调用歧义通过使用::明确调用
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "A构造" << this << endl;
}
int m_a;
void foo()
{
m_a = 10;
cout << m_a << endl;
}
};
class X :public A
{
public:
X()
{
cout << "X构造" << this << endl;
}
};
class Y :public A
{
public:
Y()
{
cout << "Y构造" << this << endl;
}
};
class Z :public X, public Y
{
public:
Z()
{
cout << "Z构造" << this << endl;
}
};
int main()
{
Z z;
//z.foo(); 调用不明确 z对象中有X和Y的对象,X和Y中有A的对象
//不知道调用X->A.foo 还是调用Y->A.foo();
z.X::foo();
z.Y::foo();
//z.A::foo();
z.X::A::foo();
return 0;
}
在公共基类继承方式前加关键字virtual 在公共基类对象保存到公共位置,存储偏移值
虚继承是为了解决棱形继承中成员访问的二义性。在A B继承方式前加关键字virtual,编译器将Base的数据保存在一个公共位置,通过虚基表访问。
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "A构造" << this << endl;
}
int m_a;
int m_b;
void foo()
{
m_a = 10;
cout << m_a << endl;
}
};
/*
* 解决方法二:虚继承基类A
*/
class X :virtual public A
{
public:
X()
{
cout << "X构造" << this << endl;
}
};
class Y :virtual public A
{
public:
Y()
{
cout << "Y构造" << this << endl;
}
};
class Z :public X, public Y
{
public:
Z()
{
cout << "Z构造" << this << endl;
}
};
int main()
{
cout << "A:" << sizeof(A) << ",X:" << sizeof(X) << ",Y:" << sizeof(Y) << ",Z:" << sizeof(Z) << endl;
Z z;
//z.foo(); //对“foo”的访问不明确
/*
* 解决方法一:作用域::这么调用哪个父类里面的foo函数
*/
//z.X::foo();
//z.Y::foo();
z.foo(); //虚继承解决棱形继承问题
cin.get();
return 0;
}
A:4,X:8,Y:8,Z:12
A构造00F6F994
X构造00F6F98C
Y构造00F6F990
Z构造00F6F98C
10
End