您好,登錄后才能下訂單哦!
組合關(guān)系是整體與部分的關(guān)系。
組合關(guān)系的特點:
A、將其它類的對象作為當前類的成員使用
B、當前類的對象與成員對象的生命周期相同
C、成員對象在用法上與普通對象相同
Computer類由其它多個部件類組合而成,當Computer銷毀時,其它部件對象同時銷毀。
#include <iostream>
using namespace std;
class Memory
{
public:
Memory()
{
cout << "Memory()" << endl;
}
~Memory()
{
cout << "~Memory()" << endl;
}
};
class Disk
{
public:
Disk()
{
cout << "Disk()" << endl;
}
~Disk()
{
cout << "~Disk()" << endl;
}
};
class CPU
{
public:
CPU()
{
cout << "CPU()" << endl;
}
~CPU()
{
cout << "~CPU()" << endl;
}
};
class MainBoard
{
public:
MainBoard()
{
cout << "MainBoard()" << endl;
}
~MainBoard()
{
cout << "~MainBoard()" << endl;
}
};
class Computer
{
Memory mMem;
Disk mDisk;
CPU mCPU;
MainBoard mMainBoard;
public:
Computer()
{
cout << "Computer()" << endl;
}
void power()
{
cout << "power()" << endl;
}
void reset()
{
cout << "reset()" << endl;
}
~Computer()
{
cout << "~Computer()" << endl;
}
};
int main(int argc, char *argv[])
{
Computer c;
c.reset();
return 0;
}
繼承關(guān)系是類之間的父子關(guān)系。繼承關(guān)系的特點如下:
A、子類擁有父類的所有屬性和行為
B、子類也是一種特殊的父類
C、子類對象可以當父類對象使用
D、子類中可以添加父類沒有的屬性和方法
E、子類對象可以直接初始化為父類對象
F、子類對象可以直接賦值給父類對象
G、繼承是面向?qū)ο缶幊讨写a復(fù)用的重要手段
#include <iostream>
using namespace std;
class Parent
{
public:
Parent(int i = 0)
{
member = i;
}
void method()
{
cout << "member = " << member << endl;
}
private:
int member;
};
class Child : public Parent
{
public:
Child(int i = 0, int j = 0):Parent(i)
{
childMember = j;
}
void childMethod()
{
method();
cout << "childMember = "<< childMember << endl;
}
private:
int childMember;
};
int main(int argc, char *argv[])
{
Child child(1,2);
child.method();
child.childMethod();
return 0;
}
定義類時根據(jù)類的設(shè)計需求確定成員的訪問級別,規(guī)則如下:
A、public修飾的成員可以被外部訪問。
B、protected修飾的成員不可以被外部訪問,但可以被子類訪問。
C、private修飾的成員不可以被外部和子類訪問。
#include <iostream>
using namespace std;
class Parent
{
public:
Parent(int a = 0, int b = 0, int c = 0)
{
pub = a;
pro = b;
pri = c;
}
void method()
{
cout << "pub = " << pub << endl;
cout << "pro = " << pro << endl;
cout << "pri = " << pri << endl;
}
public:
int pub;
protected:
int pro;
private:
int pri;
};
class Child : public Parent
{
public:
Child(int a = 0, int b = 0):Parent(a, b)
{
}
void childMethod()
{
pub = 100;
pro = 200;
//pri = 300;//error,子類不可見
}
};
int main(int argc, char *argv[])
{
Parent parent(1,2);
parent.pub = 1000;
//parent.pro = 2000;//error,外部不可見
//parent.pri = 3000;//error,外部不可見
Child child(1,2);
child.pub = -1000;
//child.pro = -2000;//error,外部不可見
//child.pri = -3000;//error,外部不可見
child.childMethod();
return 0;
}
在C++編程中,軟件可重用性(software reusability)是通過繼承(inheritance)機制來實現(xiàn)的。類的繼承,是新的類從已有類得到已有的特性。從已有類產(chǎn)生新類的過程就是類的派生。原有的類稱為基類或父類,產(chǎn)生的新類稱為派生類或子類。
繼承是一種封裝模型之間關(guān)系的抽象,是不同封裝模型的層次分類。
派生類的聲明:
class 派生類名:[繼承方式] 基類名
{
派生類成員聲明;
};
如果一個派生類同時有多個基類,稱為多重繼承;如果派生類只有一個基類,稱為單繼承。
繼承方式規(guī)定了如何訪問基類繼承的成員。繼承方式有public、 private,、protected。繼承方式指定了派生類成員以及類外對象對于從基類繼承來的成員的訪問權(quán)限。繼承方式如下:
A、公有繼承
基類的公有成員和保護成員在派生類中保持原有訪問屬性,其私有成員仍為基類的私有成員。
B、私有繼承
基類的公有成員和保護成員在派生類中成了私有成員,其私有成員仍為基類的私有成員。
C、保護繼承
基類的公有成員和保護成員在派生類中成了保護成員,其私有成員仍為基類的私有成員。
不同繼承方式下父類成員的訪問級別如下:
繼承成員的訪問屬性 = Max{繼承方式,父類成員的訪問屬性}
使用class關(guān)鍵字定義派生類時,默認繼承方式為private。
使用struct關(guān)鍵字定義派生類時,默認繼承方式為public。
C++工程項目中,通常只使用public繼承方式。
#include <iostream>
using namespace std;
class Parent
{
public:
Parent(int a = 0, int b = 0, int c = 0)
{
pub = a;
pro = b;
pri = c;
}
public:
int pub;
protected:
int pro;
private:
int pri;
};
class ChildA : public Parent
{
public:
ChildA(int a = 0, int b = 0):Parent(a, b)
{
}
void print()
{
cout << "pub = " << pub << endl;
cout << "pro = " << pro << endl;
//cout << "pri = " << pri << endl;//error,私有成員不可見
}
};
class ChildB : protected Parent
{
public:
ChildB(int a = 0, int b = 0):Parent(a, b)
{
}
void print()
{
cout << "pub = " << pub << endl;
cout << "pro = " << pro << endl;
//cout << "pri = " << pri << endl;//error,私有成員不可見
}
};
class ChildC : private Parent
{
public:
ChildC(int a = 0, int b = 0):Parent(a, b)
{
}
void print()
{
cout << "pub = " << pub << endl;
cout << "pro = " << pro << endl;
//cout << "pri = " << pri << endl;//error,私有成員不可見
}
};
//默認繼承方式
class ChildD : Parent
{
public:
ChildD(int a = 0, int b = 0):Parent(a, b)
{
}
void print()
{
cout << "pub = " << pub << endl;
cout << "pro = " << pro << endl;
//cout << "pri = " << pri << endl;//error,私有成員不可見
}
};
int main(int argc, char *argv[])
{
ChildA childa(1000,2000);
childa.pub = 0;
//childa.pro = 2000;//error,外部不可見
//childa.pri = 3000;//error,外部不可見
childa.print();
ChildB childb(1001,2001);
//childb.pub = 1001;//error,外部不可見
//childb.pro = 2001;//error,外部不可見
//childb.pri = 3001;//error,外部不可見
childb.print();
ChildC childc(1002,2002);
//childc.pub = 1002;//error,外部不可見
//childc.pro = 2002;//error,外部不可見
//childc.pri = 3002;//error,外部不可見
childc.print();
ChildD childd(1003,2003);
//childd.pub = 1003;//error,外部不可見
//childd.pro = 2003;//error,外部不可見
//childd.pri = 3003;//error,外部不可見
childd.print();
return 0;
}
派生類中的成員包含兩大部分,一類是從基類繼承過來的,一類是自己增加的成員。從基類繼承的成員表現(xiàn)其共性,而新增的成員體現(xiàn)其個性。
派生類中由基類繼承而來的成員的初始化工作還是由基類的構(gòu)造函數(shù)完成,然后派生類中新增的成員在派生類的構(gòu)造函數(shù)中初始化。派生類沒有繼承基類的構(gòu)造函數(shù)和析構(gòu)函數(shù)。
派生類的構(gòu)造函數(shù)語法如下:
派生類名::派生類名(參數(shù)總表)
:基類名(參數(shù)表),內(nèi)嵌子對象(參數(shù)表)
{
派生類新增成員的初始化語句; //也可出現(xiàn)在參數(shù)列表中
}
子類構(gòu)造函數(shù)必須對繼承來的成員進行初始化,可以直接通過初始化列表或賦值方式進行,也可以調(diào)用父類構(gòu)造函數(shù)進行初始化。
父類構(gòu)造函數(shù)在子類中的調(diào)用方式:
A、默認調(diào)用,適用于無參構(gòu)造函數(shù)和使用默認參數(shù)的構(gòu)造函數(shù)
B、顯示調(diào)用,適用于所有父類構(gòu)造函數(shù),通過初始化列表調(diào)用
#include <iostream>
#include <string>
using namespace std;
class Parent
{
public:
Parent()
{
cout << "Parent()" << endl;
}
Parent(string s)
{
cout << "Parent(string s): " << s << endl;
}
~Parent()
{
cout << "~Parent()" << endl;
}
};
class Child : public Parent
{
public:
//隱式調(diào)用父類的無參構(gòu)造函數(shù)或默認參數(shù)構(gòu)造函數(shù)
Child()
{
cout << "Child()" << endl;
}
//顯示調(diào)用父類構(gòu)造函數(shù),如果不顯示調(diào)用,默認調(diào)用
//父類的無參構(gòu)造函數(shù)或默認參數(shù)構(gòu)造函數(shù)
Child(string s):Parent(s)
{
name = s;
cout << "Child(): " << s << endl;
}
~Child()
{
cout << "~Child(): " << name << endl;
}
private:
string name;
};
int main(int argc, char *argv[])
{
Child child1("bauer");
// output:
// Parent(string s): bauer
// Child(): bauer
// ~Child(): bauer
// ~Parent()
return 0;
}
構(gòu)造函數(shù)的調(diào)用順序不以初始化列表中的調(diào)用順序進行,而是根據(jù)類中對成員變量聲明的順序進行調(diào)用。如果基類中沒有默認構(gòu)造函數(shù)(無參),那么在派生類的構(gòu)造函數(shù)中必須顯示調(diào)用基類構(gòu)造函數(shù),以初始化基類成員。
派生類對象創(chuàng)建時構(gòu)造函數(shù)的調(diào)用順序如下:
A、調(diào)用基類構(gòu)造函數(shù),調(diào)用順序按照基類被繼承時聲明的順序(從左到右);
B、調(diào)用成員變量的構(gòu)造函數(shù),調(diào)用順序按照成員變量在類中聲明的順序;
C、調(diào)用派生類自身的構(gòu)造函數(shù)。
子類構(gòu)造函數(shù)中,要么顯示的調(diào)用父類的構(gòu)造函數(shù)(傳參),要么隱式的調(diào)用。發(fā)生隱式調(diào)用時,父類要有無參構(gòu)造函數(shù)或是可以包含無參構(gòu)造函數(shù)的默認參數(shù)函數(shù)。子類構(gòu)造函數(shù)必須對繼承而來的成員進行初始化,可以通過初始化列表或者賦值的方法進行初始化,也可以通過調(diào)用父類構(gòu)造函數(shù)進行初始化。
子類對象創(chuàng)建時構(gòu)造函數(shù)的調(diào)用順序如下:
A、調(diào)用父類的構(gòu)造函數(shù)
B、調(diào)用成員變量的構(gòu)造函數(shù)
C、調(diào)用類自身的構(gòu)造函數(shù)
#include <iostream>
using namespace std;
class Parent
{
public:
Parent()
{
cout << "Parent()" << endl;
}
Parent(string s)
{
cout << "Parent(string s): " << s << endl;
}
~Parent()
{
cout << "~Parent()" << endl;
}
};
class Member
{
public:
Member(int i = 0)
{
this->i = i;
cout << "Member(int i = 0) i = " << i << endl;
}
~Member()
{
cout << "~Member() i = " << i << endl;
}
private:
int i;
};
class Child : public Parent
{
public:
//隱式調(diào)用父類的無參構(gòu)造函數(shù)或默認參數(shù)構(gòu)造函數(shù)
Child()
{
cout << "Child()" << endl;
}
//顯示調(diào)用父類構(gòu)造函數(shù),如果不顯示調(diào)用,默認調(diào)用
//父類的無參構(gòu)造函數(shù)或默認參數(shù)構(gòu)造函數(shù)
Child(string s, int i):Parent(s),member(i)
{
name = s;
cout << "Child(): " << s << endl;
}
~Child()
{
cout << "~Child(): " << name << endl;
}
private:
string name;
Member member;
};
int main(int argc, char *argv[])
{
Child childA("bauer", 10);
// output:
// Parent(string s): bauer
// Member(int i = 0) i = 10
// Child(): bauer
// ~Child(): bauer
// ~Member() i = 10
// ~Parent()
return 0;
}
派生類拷貝構(gòu)造函數(shù)的定義如下:
派生類::派生類(const 派生類& another)
:基類(another),派生類新成員(another.新成員)
{
}
派生類中的默認拷貝構(gòu)造函數(shù)會調(diào)用父類中默認或自實現(xiàn)拷貝構(gòu)造函數(shù),若派生類中自實現(xiàn)拷貝構(gòu)造函數(shù),則必須顯示的調(diào)用父類的拷貝構(gòu)造函數(shù)。
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
Student(string sn,int n,char s)
{
name = sn;
num = n;
sex = s;
cout << "Student(string sn,int n,char s)" << endl;
}
Student(const Student& another)
{
name = another.name;
num = another.num;
sex = another.sex;
}
~Student()
{
cout << "~Student()" << endl;
}
void print()
{
cout << name << endl;
cout << num << endl;
cout << sex << endl;
}
private:
string name;
int num;
char sex;
};
class Graduate : public Student
{
public:
Graduate(string sn,int in,char cs,int fs):Student(sn, in, cs)
{
salary = fs;
cout << "Graduate(string sn,int in,char cs,float fs)" << endl;
}
~Graduate()
{
cout << "~Graduate()" << endl;
}
Graduate(const Graduate& another):Student(another)
{
salary = another.salary;
}
void display()
{
print();
cout<<salary<<endl;
}
private:
int salary;
};
int main(int argc, char *argv[])
{
Graduate s("bauer", 1001,'M',8000);
s.display();
Graduate g = s;
g.display();
return 0;
}
派生類的賦值操作符重載函數(shù)的定義如下:
子類& 子類::operator=(const 子類& another)
{
if(this != &another)
{
父類::operator =(another); // 調(diào)用父類的賦值運算符重載
this->salary = another.salary;//子類成員初始化
}
return * this;
}
派生類的如果沒有實現(xiàn)賦值操作符函數(shù),C++編譯器會提供一個默認賦值操作符重載函數(shù),默認的賦值操作符重載函數(shù)會調(diào)用父類的賦值操作符重載函數(shù)(編譯器提供的默認賦值操作符重載函數(shù)或是開發(fā)者提供的賦值操作符重載函數(shù))。
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
Student(string sn,int n,char s)
{
name = sn;
num = n;
sex = s;
cout << "Student(string sn,int n,char s)" << endl;
}
Student(const Student& another)
{
name = another.name;
num = another.num;
sex = another.sex;
}
Student& operator = (const Student& another)
{
if(this != &another)
{
name = another.name;
num = another.num;
sex = another.sex;
}
return *this;
}
~Student()
{
cout << "~Student()" << endl;
}
void print()
{
cout << name << endl;
cout << num << endl;
cout << sex << endl;
}
private:
string name;
int num;
char sex;
};
class Graduate : public Student
{
public:
Graduate(string sn,int in,char cs,int fs):Student(sn, in, cs)
{
salary = fs;
cout << "Graduate(string sn,int in,char cs,float fs)" << endl;
}
~Graduate()
{
cout << "~Graduate()" << endl;
}
Graduate(const Graduate& another):Student(another)
{
salary = another.salary;
}
void display()
{
print();
cout<<salary<<endl;
}
private:
int salary;
};
int main(int argc, char *argv[])
{
Graduate s("bauer", 1001,'M',8000);
cout << endl;
s.display();
cout << endl;
Graduate g("lee", 1002, 'F', 9000);
cout << endl;
g.display();
cout << endl;
g = s;
g.display();
cout << endl;
return 0;
}
派生類如果實現(xiàn)了賦值操作符重載函數(shù),則需在賦值操作符重載函數(shù)內(nèi)顯示地調(diào)用父類的賦值操作符重載函數(shù)。
#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
Student(string sn,int n,char s)
{
name = sn;
num = n;
sex = s;
cout << "Student(string sn,int n,char s)" << endl;
}
Student(const Student& another)
{
name = another.name;
num = another.num;
sex = another.sex;
}
Student& operator = (const Student& another)
{
if(this != &another)
{
name = another.name;
num = another.num;
sex = another.sex;
}
return *this;
}
~Student()
{
cout << "~Student()" << endl;
}
void print()
{
cout << name << endl;
cout << num << endl;
cout << sex << endl;
}
private:
string name;
int num;
char sex;
};
class Graduate : public Student
{
public:
Graduate(string sn,int in,char cs,int fs):Student(sn, in, cs)
{
salary = fs;
cout << "Graduate(string sn,int in,char cs,float fs)" << endl;
}
~Graduate()
{
cout << "~Graduate()" << endl;
}
Graduate(const Graduate& another):Student(another)
{
salary = another.salary;
}
Graduate& operator = (const Graduate& another)
{
if(this != &another)
{
Student::operator =(another);
salary = another.salary;
}
return *this;
}
void display()
{
print();
cout<<salary<<endl;
}
private:
int salary;
};
int main(int argc, char *argv[])
{
Graduate s("bauer", 1001,'M',8000);
cout << endl;
s.display();
cout << endl;
Graduate g("lee", 1002, 'F', 9000);
cout << endl;
g.display();
cout << endl;
g = s;
g.display();
cout << endl;
return 0;
}
派生類的析構(gòu)函數(shù)的功能是在對象銷毀前進行一些必要的清理工作,析構(gòu)函數(shù)沒有類型,也沒有參數(shù)。析構(gòu)函數(shù)的調(diào)用順序與構(gòu)造函數(shù)相反。
析構(gòu)函數(shù)只有一種,無重載,無默參。
子類對象銷毀時析構(gòu)函數(shù)的調(diào)用順序如下:
A、調(diào)用類自身的析構(gòu)函數(shù)
B、調(diào)用成員變量的析構(gòu)函數(shù)
C、調(diào)用父類的析構(gòu)函數(shù)
四、父類與子類的同名覆蓋
子類定義父類中的同名成員時發(fā)生同名覆蓋,規(guī)則如下:
A、子類可以定義父類中的同名成員(成員變量和成員函數(shù))
B、子類中的成員將隱藏父類中的同名成員
C、父類中的同名成員依然存在于子類中
D通過作用域訪問符訪問父類中的同名成員
如果某派生類的多個基類擁有同名的成員,派生類又新增與基類同名的成員,派生類成員將shadow(隱藏)所有基類的同名成員,需要作用域的調(diào)用方式才能調(diào)用基類的同名成員。
#include <iostream>
using namespace std;
class Parent
{
public:
int m_count;
void print()
{
cout << &m_count << endl;
}
};
class Child : public Parent
{
public:
int m_count;
void print()
{
cout << &(Parent::m_count) << endl;
cout << &m_count << endl;
}
};
int main(int argc, char *argv[])
{
Parent p;
p.print();
cout << &p.m_count << endl;
Child child;
child.print();
//子類對象的父類同名成員變量訪問
cout << &child.Parent::m_count <<endl;
//子類對象的父類同名成員函數(shù)訪問
child.Parent::print();
cout << &child.m_count << endl;
return 0;
}
函數(shù)重載發(fā)生在同一作用域 ,父類和子類的同名函數(shù)不構(gòu)成函數(shù)重載,屬于同名覆蓋,子類會隱藏父類中的同名成員。
子類可以定義父類中的同名成員,子類中的成員將隱藏父類中的同名成員,父類中的同名成員依然存在子類中,通過作用域分辨符::訪問父類中的同名成員。
子類中的成員函數(shù)將隱藏父類中的同名成員函數(shù),子類無法重載父類中同名成員函數(shù),使用作用域分辨符可以訪問父類中的同名成員函數(shù)。
#include <iostream>
using namespace std;
class Parent
{
public:
int mi;
void add(int i)
{
mi += i;
}
void add(int a, int b)
{
mi += (a + b);
}
};
class Child : public Parent
{
public:
int mi;
void add(int x, int y, int z)
{
mi += (x + y + z);
}
};
int main(int argc, char *argv[])
{
Parent p;
p.add(1);
p.add(1,2);
Child child;
child.add(1,2,3);
//child.add(1);//error
child.Parent::add(1);
//child.add(1,2);//error
child.Parent::add(1,2);
return 0;
}
賦值兼容原則是指子類對象可以作為父類對象使用。
賦值兼容原則的特點如下:
A、子類對象可以直接賦值給父類對象
B、子類對象可以直接初始化父類對象
C、父類指針可以直接指向子類對象
D、父類引用可以直接引用子類對象
當使用父類指針指向子類對象、父類引用對子類對象進行引用時,子類對象退化為父類對象,只能訪問父類中定義的成員,因此可以直接訪問被子類覆蓋的同名成員。
#include <iostream>
using namespace std;
class Parent
{
public:
int mi;
void add(int i)
{
mi += i;
}
void add(int a, int b)
{
mi += (a + b);
}
};
class Child : public Parent
{
public:
int mi;
void add(int x, int y, int z)
{
mi += (x + y + z);
}
};
int main(int argc, char *argv[])
{
Child child;
Parent p = child;
p.add(1);
p.add(1,2);
Parent& rp = child;
rp.add(1);
rp.add(1,2);
//rp.add(1,2,3);//error
Parent* pp = &child;
pp->add(1);
pp->add(1,2);
//pp->add(1,2,3);//error
return 0;
}
子類中重定義父類中已經(jīng)存在的成員函數(shù),稱為函數(shù)重寫。
函數(shù)重寫是同名覆蓋的一種特殊情況。
#include <iostream>
using namespace std;
class Parent
{
public:
int mi;
void add(int i)
{
mi += i;
}
void add(int a, int b)
{
mi += (a + b);
}
void print()
{
cout << "Parent" << endl;
}
};
class Child : public Parent
{
public:
int mi;
//函數(shù)重寫
void add(int x, int y)
{
mi += (x + y);
}
//函數(shù)重寫
void print()
{
cout << "Child" << endl;
}
};
int main(int argc, char *argv[])
{
Child child;
Parent p = child;
p.add(1);
p.add(1,2);
Parent& rp = child;
rp.add(1);
rp.add(1,2);
rp.print();//Parent
Parent* pp = &child;
pp->add(1);
pp->add(1,2);
pp->print();//Parent
return 0;
}
C++是一種靜態(tài)編譯語言,在編譯期間,C++編譯器只能根據(jù)指針的類型判斷所指向的對象。根據(jù)賦值兼容原則,C++編譯器認為父類指針指向的是父類對象,父類引用是對父類對象的引用,因此編譯結(jié)果只能是調(diào)用父類中定義的同名函數(shù)。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。