1.1 封装的概念
封装:通过访问控制属性对类类型中的属性和行为进行打包和限制.
1.2 继承:通过一种机制表达出类型之间的共性和特性的方式.
继承基本语法:class 子类名 : 继承方式1 父类1,继承方式2 父类2...
{
类的定义
};
继承方式:
public 公有方式
private 私有方式
protected 保护方式1.3 继承的特性
(1) 一个子类类型的对象在任何时候都可以看作基类类型的对象(心里始终要记着).
(2) 一个父类类型的对象作为子类对象去使用,有可能引发段错误.
(3) 在子类中可以访问父类的公有和保护的成员,不可以访问父类中私有成员.(4) 名字的隐藏,在子类可以定义一个与父类中同名的标识符,子类隐藏父类.(不能构成重载,不在同一作用域下,函数参数也不一定一致.)
(5) 如果非要调用父类中的同名函数,那么可以显示指定 父类::函数名;1.4 继承方式和访问控制
限定符 访控属性 本类 子类 外部 友元
---------------------------------------------------------
public 公开的 ok ok ok ok
protected 保护的 ok ok no ok
private 私有的 ok no no ok
---------------------------------------------------------
1.5继承方式对访控属性的影响
基类访控 公有子类 保护子类 私有子类
public public protected private
protected protected protected private
private private private private
注意:规则优先选择保护性最强的。一般都采用公开的继承方式,其他两种继承方式很少。
继承例子代码如下:
class CPerson
{
private:
string m_name;
int m_age;
public:
CPerson(const string& name,int age):m_name(name),m_age(age)
{
cout<<"CPerson类==》"<<"我是 "<<m_name<<"今年 "<<m_age<<"岁了"<<endl;
}
void eat(const string& str)
{
cout<<"这是父类的eat函数"<<endl;
}
protected:
string getName()
{
return m_name;
}
int getAge()
{
return m_age;
}
};
class CStudent : public CPerson
{
private:
int m_num;
public:
CStudent(const string& name,int age,int num):CPerson(name,age),m_num(num)
{
cout<<"我是学生, 我的学号是: "<<m_num<<endl;
}
void lean(const string& strlesson)
{
cout<<"我在学习 "<<strlesson<<endl;
}
void print(void)
{
cout<<"学习学号: "<<m_num<<endl;
}
void show(void)
{
cout<<"我是"<<getName()<<"今年"<<getAge()<<"学习学号"<<m_num<<endl;
}
void eat(const string& foot)
{
cout<<"这是子类中的eat函数"<<endl;
}
};
class CTeacher : public CPerson
{
private:
string m_job;
public:
CTeacher(const string& name,int age,const string& job):CPerson(name,age),m_job(job)
{
cout<<"我是教师,我的职称是: "<<m_job<<endl;
}
void tech(const string& lesson)
{
cout<<"我在教"<<lesson<<endl;
}
};
1.6子类的构造函数和析构函数
(1)在子类的构造函数中可以显示的指定其基类的构造方式(:基类(参数)),如果没有显示的指定,那么系统就会以无参的形式去构造基类的部分。
(2)子类的析构函数会自动的调用父类的析构函数,但是基类的析构函数不会自动调用子类的析构函数。( 这个是指子类对象析构的时候哦)(3)如果父类指针指向子类对象,那么delete指针时,被调用的仅仅是父类的析构函数,子类的析构函数不会被调用,为了调用子类的析构函数,采用虚析构
class A
{
public:
A()
{
cout<<"A is create"<<endl;
}
virtual ~A()
{
cout<<"A is delete"<<endl;
}
};
class B :public A
{
public:
B()
{
cout<<"B is create"<<endl;
}
~B()
{
cout<<"B is delete"<<endl;
}
};
B* pb = new B();
delete pb;
pb = NULL;
调用输出顺序为:
A is create
<span style="font-family: Arial, Helvetica, sans-serif;">B is create</span>
<span style="font-family: Arial, Helvetica, sans-serif;">B is delete</span>
<pre name="code" class="cpp"><pre name="code" class="cpp"><span style="font-family: Arial, Helvetica, sans-serif;">A is delete</span>
可以看构造和析构的顺序严格相反
1.7子类的拷贝构造和拷贝赋值函数
(1)如果在子类中需要自定义拷贝构造函数,那么需要在拷贝构造函数中显式的指明调用父类的拷贝构造函数,拷贝赋值也是一样。class Teacher; //类的前项声明
class Person
{
private:
string m_name;
int m_age;
public:
Person(const string& name,int age):m_name(name),m_age(age)
{
cout<<"Person类==》"<<"我是 "<<m_name<<"今年 "<<m_age<<"岁了"<<endl;
}
Person(const Person& p):m_name(p.m_name),m_age(p.m_age)
{
cout<<"Person类中的自定义拷贝构造函数被调用"<<endl;
}
void eat(const string& str)
{
cout<<"这是父类的eat函数"<<endl;
}
protected:
string getName()
{
return m_name;
}
int getAge()
{
return m_age;
}
};
class Teacher : public Person
{
private:
string m_job;
public:
Teacher(const string& name,int age,const string& job):Person(name,age),m_job(job)
{
cout<<"我是教师,我的职称是: "<<m_job<<endl;
}
Teacher(const Teacher& t):Person(t),m_job(t.m_job) //<span style="color:#ff6666;">子类类型对象可以作为父类类型对象使用哦,显示调用其拷贝构造函数</span>
{
cout<<"Teacher类中的自定义的拷贝构造函数被调用"<<endl;
}
void tech(const string& lesson)
{
cout<<"我在教"<<lesson<<endl;
}
};
二、多重继承(钻石继承)
员工类(姓名)
/ \
领导类 销售人员类
\ /
销售人员领导类(保证只有一个名字.)
钻石继承注意:
(1)在对公共继承的继承方式之前加virtual关键字.(虚继承)(2)可能需要在最终子类中显示指明公共基类的构造方式(可能缺省构造也可以实现)
(3)目标:公共基类在最后子类中只有一份,以避免由不同继承路径访问公共基类时发生数据不一致.
注意:在多继承中,如果多个父类都有函数名相同,参数表不同的函数,继承到子类中不会构成重载.说明对钻石继承我在下面运行的结果我使用一个图示表示:
<span style="white-space:pre"> </span>DD dd(100);
cout<<"m_data = "<<dd.GetValue()<<endl;
dd.SetValue(1000);
cout<<"m_data = "<<dd.GetValue()<<endl;
<span style="white-space:pre"> </span>没有使用虚继承时输出结果如下:100,100
<span style="white-space:pre"> </span>使用虚继承时输出结果如下:100,1000
class AA
{
public:
int m_data;
public:
AA(int data):m_data(data)
{
cout<<"AA is create"<<endl;
}
~AA()
{
cout<<"AA is delete"<<endl;
}
};
class BB : virtual public AA
{
public:
BB(int n):AA(n)
{
cout<<"BB is create"<<endl;
}
void SetValue(int nValue)
{
m_data = nValue;
}
void show()
{
cout<<"B类中show函数"<<endl;
}
~BB()
{
cout<<"BB is delete"<<endl;
}
};
class CC : virtual public AA
{
public:
CC(int n):AA(n)
{
cout<<"CC is create"<<endl;
}
int GetValue()
{
return m_data;
}
void show(int i)
{
cout<<"C类中的一个show函数"<<endl;
}
~CC()
{
cout<<"CC is delete"<<endl;
}
};
class DD : public BB,public CC
{
public:
DD(int n):CC(n),BB(n),AA(n)/*显示指定调用AA的构造*/
{
cout<<"DD is create"<<endl;
}
~DD()
{
cout<<"DD is delete"<<endl;
}
void show(char c,int n)
{
cout<<"DD 类中的show函数"<<endl;
}
};
int main(void)
{
DD dd(100);
cout<<"m_data = "<<dd.GetValue()<<endl;
dd.SetValue(1000);
cout<<"m_data = "<<dd.GetValue()<<endl;
cout<<"-------------------------------------"<<endl;
dd.BB::show(); //指定调用B类中的show函数.
dd.show('c',10);
cout<<"--------------------------------"<<endl;
Teacher t1("weikangc",25,"教授");
t1.eat("包子");
t1.tech("Java");
cout<<"---------------------------------"<<endl;
Teacher t2(t1);
t2.tech("C++");
B b;
A& a = b;
A* pA = new B;
delete pA;
pA = NULL;
B* pB = new B;
delete pB;
pB = NULL;
CStudent s1("weikangc",25,6888);
s1.lean("C++");
s1.CPerson::eat("拉面");
s1.show();
//s1.getName(); //保护类的成员不可以在类的外部使用.
//s1.getAge();
cout<<"-------------------------------------"<<endl;
CTeacher c1("WeiKangC",28,"Java讲师");
c1.eat("包子");
c1.tech("Java");
cout<<"--------------------------------------"<<endl;
CPerson* person = new CStudent("程伟康",25,99999);
person->eat("羊肉汤");
//person->lean("C/C++,JAVA"); //编译报错,没有此函数,编译器只关注数据类型,发现此类型中没有该函数.
CStudent* pS = static_cast<CStudent*>(person);
pS->lean("C/C++");
pS->print();
delete person;
person = NULL;
cout<<"---------------------------------------"<<endl;
CStudent* ppS = static_cast<CStudent*>(new CPerson("伟康程",26));
ppS->lean("Win32");
ppS->CPerson::eat("炒鸡");
ppS->print(); //缺少一个成员比较危险.
delete ppS;
ppS = NULL;
return 0;
}