4.5.3遞增運算符重載
作用:通過重載遞增運算符历恐,實現(xiàn)自己的整形數(shù)據(jù)
1.前置++
2.后置++(重載時引入占位參數(shù)int躏率,用以告知編輯器為后置遞增)
總結(jié):前置遞增返回引用嫂沉,后置遞增返回值
示例:
//自定義整型
class MyInteger
{
friend ostream &operator <<(ostream &os, MyInteger myint);
public:
MyInteger()
{
m_Num = 0;
}
//重載前置++運算符
//返回引用是為了一直對一個數(shù)據(jù)進行遞增操作
MyInteger& operator++()
{
++m_Num;
return *this;
}
//重載后置++運算符
//int代表占位參數(shù)殴蓬,用于區(qū)分前置和后置遞增
//一定要返回值柏蘑,因為返回局部對象的引用是非法操作
//先返回庙曙,后++
MyInteger operator++(int )
{
MyInteger temp = *this;//記錄當前本身的值
++m_Num;
return temp;
}
private:
int m_Num;
};
ostream &operator <<(ostream &os, MyInteger myint)
{
os << myint.m_Num;
return os;
}
void test01()
{
MyInteger myint;
cout <<++myint << endl;
cout << myint << endl;
}
void test02()
{
MyInteger myint;
cout << myint++ << endl;
cout << myint << endl;
}
4.5.4賦值運算符重載
C++至少給一個類添加4個函數(shù):
1.默認構(gòu)造函數(shù)(無參空镜,函數(shù)體為空)
2.默認析構(gòu)函數(shù)(無參,函數(shù)體為空)
3.默認拷貝構(gòu)造函數(shù)捌朴,對屬性進行值拷貝吴攒;
4.賦值運算符operator=,對屬性進行值拷貝
如果類中有屬性指向堆區(qū)砂蔽,做賦值操作時也會出現(xiàn)深淺拷貝問題洼怔;
淺拷貝:堆區(qū)內(nèi)存重復釋放,程序崩潰左驾;
解決方案:利用深拷貝镣隶,解決淺拷貝帶來的問題;
示例:
class Person
{
public:
Person(int age)
{
m_Age = new int(age);
cout << "Person(int)" << endl;
}
//注意:返回的是引用诡右,才能返回對象自身
Person& operator=(const Person &p)
{
//m_Age = p.m_Age;//編譯器提供的淺拷貝
//應(yīng)該先判斷是否有屬性在堆區(qū)安岂,如果有,先釋放干凈
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
//然后再深拷貝
m_Age = new int(*p.m_Age);
return *this;
}
~Person()
{
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
cout << "~Person()" << endl;
}
//private:
int *m_Age;
};
4.5.5關(guān)系運算符重載
1.推薦:友元函數(shù)的形式重載
2.也可成員函數(shù)形式重載
4.5.6函數(shù)調(diào)用運算符重載
1.函數(shù)調(diào)用運算符()也可以重載帆吻;
2.由于重載后使用方式非常像函數(shù)調(diào)用嗜闻,因此稱為仿函數(shù);
3.仿函數(shù)沒有固定寫法桅锄,非常靈活;
補充:不想創(chuàng)建一個對象時样眠,可使用匿名函數(shù)對象友瘤;
示例:
//打印輸出類
class MyPrint
{
public:
void operator()(string test)
{
cout << test << endl;
}
};
//仿函數(shù)非常靈活,沒有固定寫法
class MyAdd
{
public:
int operator()(int a, int b)
{
return a + b;
}
};
void test01()
{
MyPrint myp;
myp("lalalala");//由于使用起來非常類似于函數(shù)調(diào)用檐束,因此稱為仿函數(shù)
}
void test02()
{
MyAdd myadd;
cout<<myadd(5, 9)<<endl;
//匿名函數(shù)對象
cout << MyAdd()(10, 10) << endl;
}
4.6繼承
4.6.1繼承基本語法
繼承時面向?qū)ο笕筇匦灾唬?/p>
利用繼承技術(shù)辫秧,可以減少重復代碼;
語法:class 子類(派生類) : 繼承方式? 父類(基類)
4.6.2繼承方式
共三種:
1.公共繼承
2.保護繼承
3.私有繼承
4.6.3繼承中的對象模型
如何使用工具查看vs中的對象模型:
利用開發(fā)人員命令提示工具查看對象模型
1.跳轉(zhuǎn)盤符? D:
2.跳轉(zhuǎn)文件路徑 cd ..具體路徑下
3.查看命令
cl /d1 reportSingleClassLayout 類名 文件名(.cpp)
示例:
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son
:public Base
{
public:
int m_D;
};
void test01()
{
//父類中所有非靜態(tài)成員屬性都會被子類繼承下去
//父類中私有成員屬性 是被編譯器隱藏了
//因此是訪問不到被丧,但是確實被繼承下去了
cout << "sizeof(Son)=" << sizeof(Son) << endl;
}
注意:父類中的私有成員也被子類繼承了盟戏,只是訪問不到
4.6.4繼承中的構(gòu)造和析構(gòu)順序
先調(diào)用父類構(gòu)造函數(shù),再調(diào)用子類構(gòu)造函數(shù)甥桂;
析構(gòu)順序與構(gòu)造相反柿究;
4.6.5繼承同名成員處理方式
1.訪問子類同名成員,直接訪問即可黄选;
2.訪問父類同名成員蝇摸,需要加作用域婶肩;
示例:
class Base
{
public:
void func()
{
cout << "Base::func()" << endl;
}
void func(int a)
{
cout << "Base::func(int)" << endl;
}
};
class Son
:public Base
{
public:
void func()
{
cout << "Son::func()" << endl;
}
};
void test03()
{
Son s;
//如果子類中出現(xiàn)和父類同名的成員函數(shù)
//子類的同名成員會隱藏掉父類中所有同名成員函數(shù)
//“所有”是指只要函數(shù)名相同,哪怕參數(shù)不同
//如果想訪問到父類中被隱藏的同名成員函數(shù)貌夕,需要加作用域
//s.func(100);//error
s.Base::func(100);
}
總結(jié):
1.子類對象可以直接訪問到子類中的同名成員律歼;
2.子類對象加作用域可以訪問到父類同名成員;
3.當父類和子類擁有同名的成員函數(shù)啡专,子類會隱藏父類中同名成員函數(shù)险毁,加作用域可以訪問到父類中的同名成員函數(shù);
4.6.6繼承同名靜態(tài)成員處理方式
靜態(tài)成員和非靜態(tài)成員出現(xiàn)同名们童,處理方式一致畔况;
1.訪問子類同名成員,直接訪問即可病附;
2.訪問父類同名成員问窃,需要加作用域;
注意:靜態(tài)成員可以通過類名訪問完沪;
示例:
void test01()
? {
? //1.通過對象訪問
? /*Son s;
? cout << "Base::m_A=" << s.Base::m_A << endl;
? cout << "Son::m_A=" << s.m_A << endl;*/
? //2.通過類名訪問
? cout << "Base::m_A=" << Base::m_A << endl;
? cout << "Son::m_A=" << Son::m_A << endl;
? //第一個::代表通過類名方式訪問?
? //第二個::代表訪問父類作用域下
? cout << "Base::m_A=" << Son::Base::m_A << endl;
? }
? void test02()
? {
? //1.通過對象訪問
? Son s;
? s.func();
? s.Base::func();
? //2.通過類名訪問
? Son::func();
? Son::Base::func();
? }