原始类的写法
class News
{
public:
void header()
{
cout << "公共首部栏" << endl;
}
void footer()
{
cout << "公共底部栏" << endl;
}
void left()
{
cout << "左侧列表" << endl;
}
void content()
{
cout << "新闻播放" << endl;
}
};
class Plays
{
public:
void header()
{
cout << "公共首部栏" << endl;
}
void footer()
{
cout << "公共底部栏" << endl;
}
void left()
{
cout << "左侧列表" << endl;
}
void content()
{
cout << "娱乐播报" << endl;
}
};
void test02()
{
News news;
news.header();
news.footer();
news.left();
news.content();
Plays plays;
plays.header();
plays.footer();
plays.left();
plays.content();
}
继承:减少代码的重复性
class BasePage //基类(父类)
{
public:
void header()
{
cout << "公共首部栏" << endl;
}
void footer()
{
cout << "公共底部栏" << endl;
}
void left()
{
cout << "左侧列表" << endl;
}
};
class News :public BasePage //派生类(子类)
{
public:
void content()
{
cout << "新闻播放" << endl;
}
};
class Plays :public BasePage //派生类(子类)
{
public:
void content()
{
cout << "娱乐播报" << endl;
}
};
class Games :public BasePage //派生类(子类)
{
public:
void content()
{
cout << "游戏直播" << endl;
}
};
void test02()
{
News news;
news.header();
news.footer();
news.left();
news.content();
Plays plays;
plays.header();
plays.footer();
plays.left();
plays.content();
Games games;
games.header();
games.footer();
games.left();
games.content();
}
继承方式
- 公有继承:不可访问private属性,可访问public、protected属性
- 保护继承:不可访问private属性,把public、protected属性都变成protected属性
- 私有继承:不可放问private属性,把public、protected属性都变成private属性
class Son1 :public Base1 //公有继承
{
public:
void func()
{
cout << m_A << endl; //仍然是public属性
cout << m_B << endl; //仍然是protected属性
//cout << m_C << endl; //基类中私有属性不可继承
}
};
class Son2 :protected Base1 //保护继承
{
public:
void func()
{
cout << m_A << endl; //变成protected属性
cout << m_B << endl; //变成protected属性
//cout << m_C << endl; //基类中私有属性不可继承
}
};
class Son3 :private Base1 //私有继承
{
public:
void func()
{
cout << m_A << endl; //变成private属性
cout << m_B << endl; //变成private属性
//cout << m_C << endl; //基类中私有属性不可继承
}
};
void myFunc()
{
Son1 s1;
s1.m_A;
//s1.m_B; //不可访问
//s1.m_C; //不可访问
Son2 s2;
//s2.m_A; //不可访问
//s1.m_B; //不可访问
//s1.m_C; //不可访问
Son3 s3;
//s2.m_A; //不可访问
//s1.m_B; //不可访问
//s1.m_C; //不可访问
}
继承中的对象模型
子类中 会继承父类的私有成员,只是被编译器给隐藏起来,访问不到私有成员
//继承中的对象模型
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son :public Base
{
public:
int m_D;
};
void test03()
{
//子类中 会继承父类的私有成员,只是被编译器给隐藏起来,访问不到私有成员
cout << sizeof(Son) << endl; //输出16 = 4x4
}
c1 /d1 reportSingleClassLayoutSon(类名) test.cpp(文件名)用开发人员命令提示符查看类的继承模型
继承中的构造和析构顺序
构造顺序:先调用父类的构造,然后调用自身构造;析构顺序:先调用自身析构,然后调用父类的析构
-
子类不会继承父类的构造函数和析构函数 只有父类自己知道如何构造和析构自己的属性,而子类不知道
-
如果父类中没有合适默认构造,那么子类可以利用初始化列表的方式显示的调用父类的其他构造
-
子类不会继承重载函数operator=()
//继承中的构造和析构顺序
//子类不会继承父类的构造函数和析构函数 只有父类自己知道如何构造和析构自己的属性,而子类不知道
//如果父类中没有合适默认构造,那么子类可以利用初始化列表的方式显示的调用父类的其他构造
class Base2
{
public:
Base2(int a)
{
this->m_A = a;
cout << "有参构造函数调用" << endl;
}
int m_A;
};
class Son4 :public Base2
{
public:
Son4(int a):Base2(10) //利用初始化列表方式 显示调用 有参构造
{
}
};
void test04()
{
Son4 s2(1000);
}
继承中的同名处理
如果子类和父类中有同名的属性、函数,子类会覆盖父类的属性、函数成员吗???不会
如果子类与父类的成员函数名称相同, 子类会把分类的所有的同名版本隐藏掉,如果想调用父类的方法,必须加作用域
//继承中的同名处理
class Base3
{
public:
Base3()
{
m_A = 100;
}
int m_A;
};
class Son5 :public Base3
{
public:
Son5()
{
m_A = 200;
}
int m_A;
};
void test05()
{
Son5 s1;
cout << s1.m_A << endl; //输出200 就近原则 调用子类
cout << "父类:" << s1.Base3::m_A << endl; //子类调用父类中的m_A
}
继承中的静态成员处理
与非静态成员处理类似
class Base4
{
public:
static void func()
{
cout << "Base func()" << endl;
}
static void func(int a)
{
cout << "Base func(int a)" << endl;
}
static int m_A; //静态属性 类内声明 类外初始化
};
int Base4::m_A = 1;
class Son6 :public Base4
{
public:
static void func()
{
cout << "Son6 func()" << endl;
}
static int m_A;
};
int Son6::m_A = 10;
void test06()
{
cout << Son6::m_A << endl;
cout << Base4::m_A << endl;
Son6::func(); //非静态一定要有对象
Base4::func();
}
多继承的概念以及问题
可以同时继承多个类,但容易出现二义性的问题
如果想解决二义性问题,就需要使用作用域进行区分
//多继承的概念以及问题
//可以同时继承多个类
class Base1
{
public:
Base1()
{
m_A = 10;
}
int m_A;
};
class Base2
{
public:
Base2()
{
m_B = 20;
}
int m_B;
};
class Son :public Base1, public Base2
{
public:
int m_C;
int m_D;
};
void test02()
{
cout << sizeof(Son) << endl;
Son s1;
//s1.m_A; // 容易出现二义性
cout << s1.Base1::m_A << endl;
}
菱形继承的问题以及解决方案
因为Sheep里有age,Animal也有age,这样会造成资源的浪费,因此利用虚基类virtual就可以解决该问题
SheepTuo内部结构
vbptr 虚基类指针
指向一张 虚基类表
通过表找到偏移量: 例如找到Sheep的偏移量操作:*(int *)((int *)*(int *)&st + 1)
找到共有的数据
//菱形继承的概念以及问题解决
class Animal
{
public:
int m_Age;
};
class Sheep: virtual public Animal //变成虚基类
{
public:
};
class Tuo :virtual public Animal
{
public:
};
class SheepTuo :public Sheep, public Tuo
{
public:
};
void test03()
{
SheepTup st;
st.Sheep::m_Age = 10;
st.Tuo::m_Age = 20;
//以下两个输出的结果是不一致的,但其实我们只要一份就够了,免得多开辟一份空间
cout << st.Sheep::m_Age << endl;
cout << st.Tuo::m_Age << endl;
//菱形问题的解决方案 利用虚继承
//续继承的方式就在public前面加上virtual
//以上的两个输出一样,都为20
//可以直接访问了,已经没有二义性的可能了,只存了一份数据
cout << st.m_Age << endl;
}