C++ Primer第六章!
#include "stdafx.h"
#include<iostream>
#include<string>
#include<vector>
#include<initializer_list> //實(shí)參數(shù)量未知乳讥,但是類型相同
#include<cassert> //調(diào)式頭文件柱查,assert和NDEBUG
using namespace std;
int fact_sample(int val)
{
int ret = 1;
while (val > 1)
{
ret = ret*val;
--val;
}
return ret;
}
int fact_iterator(int val)
{
int tmp = val;
if(val>1)
return tmp*fact_iterator(--val); //此處不能使用val*fact_iterator(--val),val的值會(huì)改變云石,造成表達(dá)式邏輯錯(cuò)誤唉工!
else
{
return val;
}
}
int factorial(int val)
{
if (val>1)
return val*fact_iterator(val-1); //同int fact_iterator(int val)。
else
{
return 1;
}
}
int fact_for(int val)
{
int ret = 1;
for (int i = 1; i <= val; ++i)
{
ret = ret*i;
}
return ret;
}
size_t count_calls()
{
static size_t ctr = 0; //局部靜態(tài)對(duì)象汹忠,直到程序終止才被銷毀
return ++ctr;
}
void reference_fun(int &val)
{
--val;
}
void p_fun(int *ip)
{
*ip = *ip - 1;
}
bool isShorter(const string &s1, const string &s2) //比較兩個(gè)string對(duì)象的長(zhǎng)度酵紫,string可能非常長(zhǎng)告嘲,建議使用引用!
{ //有的類型不支持拷貝(iostream奖地,其同時(shí)也不支持const)橄唬,則只能通過(guò)引用傳遞!
return s1.size() < s2.size();
}
void print_arry(const int *arry) //等價(jià)于const int[],const int[10].不允許拷貝數(shù)組参歹,但是形參還是可以寫成數(shù)組形式仰楚,其實(shí)質(zhì)是const int*
{
cout << arry[0] << endl;
}
void print_char(const char *cp)
{
if (cp)
while (*cp)
cout << *cp++;
}
void print_iter(const int *beg, const int *end)
{
while (beg != end)
cout << *beg++ << endl;
}
void print_count(const int ia[], size_t size)
{
for (size_t i = 0; i != size; ++i)
{
cout << ia[i] << endl;
}
}
void print_reference(int(&arr)[2])
{
for (auto elem : arr)
cout << elem << endl;
}
void print_mulit_ptr(int(*matptr)[2],int rowsize) //指向含有10個(gè)整數(shù)的數(shù)組的指針。而int *matptr[10]表示10個(gè)指針構(gòu)成的數(shù)組
// 等價(jià)于void print_mulit_ptr(intmatptr[][2],int rowsize)
{
for (int i = 0; i < rowsize; ++i)
{
auto *beg = begin(*matptr); //由于已知數(shù)組的大小犬庇,也可以直接使用僧界。
while (beg!=end(*matptr))
{
cout << *beg << "+";
++beg;
}
cout << endl;
++matptr;
}
}
void print_msg(initializer_list<string> lst)
{
for (auto beg = lst.begin(); beg != lst.end(); ++beg) //可以使用范圍for循環(huán)處理其中的元素
cout << *beg << " ";
cout << endl;
}
const string &shortString(const string &s1, const string &s2)
{
return s1.size() <= s2.size() ? s1 : s2;
}
void print_ret()
{
return;
}
char &get_value(string &str, string::size_type ix)
{
return str[ix];
}
vector<string> process_return()
{
return { "aaa","bbb","ccc" }; //也可以返回renturn {};返回指定類型空vector
}
int odd[2] = { 13,14 };
int even[2] = { 52,93 };
decltype(odd) *arrptr(int i)
{
return (i % 2) ? &odd : &even; //int (*p)[2]=&odd;指向10個(gè)整數(shù)的數(shù)組的定義臭挽。
}
void print_overload()
{
cout << "Test" << endl;;
}
void print_overload(const char *cp)
{
cout<<*cp<<endl;
}
void print_overload(const char *cp,string::size_type sz)
{
for (unsigned int i = 0; i < sz; ++i)
{
cout << cp[i];
}
cout << endl; //最好不在函數(shù)中定義輸出的格式捂襟。
}
const string &shorterString(const string &s1, const string &s2)
{
return s1.size() < s2.size() ? s1 : s2;
}
string &shorterString(string &s1, string &s2)
{
auto &r = shorterString(const_cast<const string&>(s1), const_cast<const string&>(s2));
return const_cast<string&>(r);
}
using sz = string::size_type;// size_t是全局定義的類型;size_type是STL類中定義的類型屬性欢峰,用以保存任意string和vector類對(duì)象的長(zhǎng)度葬荷!數(shù)組下表是size_t,而容器是size_type纽帖!
string screen(sz ht = 24, sz wid = 80, char background = ' ') //一旦某個(gè)形參被賦予了默認(rèn)值宠漩,他后面的所有形參都必須有默認(rèn)值。
{
return " "; //如果進(jìn)行多次聲明默認(rèn)實(shí)參函數(shù)懊直,則函數(shù)的后續(xù)聲明只能為沒(méi)有默認(rèn)實(shí)參的形參添加默認(rèn)值扒吁,且該形參右側(cè)所有形參都必須有默認(rèn)值!
}
inline const int &max_numbers(const int &a, const int &b)
{
return a < b ? b : a;
}
constexpr size_t arr_count(size_t cnt)
{
return 10 * cnt;
}
int addb(const int &a, const int &b)
{
return(a + b);
}
int(*p_addb)(const int &a, const int &b); //p_addb指向函數(shù)的指針室囊,其中該函數(shù)的兩個(gè)參數(shù)為const int的引用雕崩,返回值為int。
void print_addb(ostream &os, int(*print_addb)(const int &a, const int &b),const int a=3,const int b=4)
{
os << (*p_addb)(a,b) << endl;
}
int main()
{
int j_sample = fact_sample(5); //調(diào)用函數(shù)融撞,實(shí)參可以隱式轉(zhuǎn)換為形參E翁(形參初始化的機(jī)理和變量初始化一樣)
cout << j_sample << endl; //函數(shù)的返回類型不能是數(shù)組和函數(shù),但可以是指向數(shù)組或函數(shù)的指針
int j_iterator = fact_iterator(5); //在頭文件中放函數(shù)聲明懦铺,在源文件中包含頭文件,并定義函數(shù)支鸡。
cout << j_iterator << endl;
int j_for = fact_for(5);
cout << j_for << endl;
int j_reference = 5;
reference_fun(j_reference); //引用傳遞冬念,形參初始化的機(jī)理和變量初始化一樣
cout << j_reference << endl;
int j_p = 5; //指針傳遞,形參初始化的機(jī)理和變量初始化一樣
p_fun(&j_p);
cout << j_p << endl;
//void fcn(const int i){}
//void fcn(int i){} 兩個(gè)函數(shù)是一樣的牧挣,在形參拷貝初始化時(shí)急前,忽略了它的頂層const,因此給函數(shù)形參是一樣的瀑构!
//C++允許通過(guò)字面值初始化常量引用裆针,而不允許初始化普通引用!
int i_arry[10] = { 0,1,2,3 };
print_arry(i_arry);
//使用數(shù)組時(shí)確保不會(huì)越界刨摩,常見(jiàn)3種常用的技術(shù)
//數(shù)組本身包含一個(gè)結(jié)束標(biāo)記,例如C風(fēng)格字符串
char *p_char = "abc";
print_char(p_char);
//begin和end函數(shù)
int j_arry[2] = { 1,2 };
print_iter(begin(j_arry), end(j_arry));
//顯示傳遞一個(gè)數(shù)組大小
int j_count[2] = { 9,8 };
print_count(j_count, end(j_count) - begin(j_count));
//數(shù)組引用形參
int j_refer[2] = { 7,6};
print_reference(j_refer);
//傳遞多維數(shù)組
int j_mulit_arry[2][2] = { 1,2,3,4 };
print_mulit_ptr(j_mulit_arry, 2);
//可變形參的函數(shù)世吨,1澡刹、如果實(shí)參類型相同可以使用initializer_list;2耘婚、可變參數(shù)模版罢浇?
//initializer_list<T> lst;
//initializer_list<T> lst{a,b,c}; lst對(duì)象中的元素永遠(yuǎn)是常量值沐祷,即abc為const嚷闭。
//lst2=lst; 拷貝或賦值一個(gè)initializer_list對(duì)象不會(huì)拷貝列表中的元素,原始列表和副本共享元素赖临。
//lst.size();
//lst.begin(); 返回指向lst中首元素的指針胞锰。
//lst.end();
print_msg({ "aa","bb","cc" }); //向initializer_list形參中傳遞一個(gè)值的序列,必須把序列放在一對(duì)花括號(hào)內(nèi)兢榨。
//返回return
//無(wú)返回值函數(shù)嗅榕,可以使用return語(yǔ)句提前退出函數(shù)
print_ret();
//有返回值函數(shù),返回類型應(yīng)與函數(shù)類型一致色乾。返回一個(gè)值的方式和初始化一個(gè)變量或形參的方式完全一樣誊册!
string s_short1 = "aaa", s_short2 = "bbbb";
cout << shortString(s_short1, s_short2) << endl;
//返回局部變量時(shí),則返回的是局部變量的副本(未命名臨時(shí)變量)暖璧。請(qǐng)一定不要返回局部對(duì)象的引用或指針0盖印!澎办!
//引用返回值嘲碱,返回引用的函數(shù)得到左值,其他返回類型得到右值
string s_value("aaaaa");
get_value(s_value, 2) = 'B';
cout << s_value << endl;
//列表初始化返回值
vector<string> err_msg_return = process_return();
//主函數(shù)main的返回值
//mian函數(shù)的返回值可以看作狀態(tài)指示器局蚀,返回0表示執(zhí)行成功麦锯,返回其他值表示失敗。
//cstdlib中定義了兩個(gè)預(yù)處理變量琅绅,EXIT_FAILURE,EXIT_SUCCESS扶欣。
//遞歸,函數(shù)調(diào)用自身千扶,遞歸函數(shù)
cout << factorial(5) << endl;
// 返回?cái)?shù)組指針
using arrT = int[2]; //等價(jià)于typedef int arrT[10]
//arrT* func(int i),等價(jià)于int (*func(int i))[10],也可以使用C++新規(guī)定:位置返回類型
//auto func(int i) -> int(*)[10];
//如果已知函數(shù)返回的指針將指向哪個(gè)數(shù)組料祠,可以使用decltype推斷
int i_decl = 2;
int (*out_decl)[2] = arrptr(i_decl);
for (int i = 0; i < 2; ++i)
{
cout << (*out_decl)[i] << " "; //int (*p)[2]=&odd;p為指針,指向10個(gè)整數(shù)的數(shù)組澎羞。
}
cout << endl;
//重載函數(shù),在形參數(shù)量或類型上有所不同髓绽。盡量只重載那些確實(shí)非常相似的操作
const char *p_overload = "abcdefg";
print_overload();
print_overload(p_overload);
print_overload(p_overload, 3);
//頂層const形參,函數(shù)等價(jià)妆绞。底層const顺呕,函數(shù)可重載枫攀。頂層const只決定了在函數(shù)體內(nèi)是否可以改變形參值,而不影響傳入的實(shí)參株茶。
//int lookup(int),int lookup(const int); int lookup(int*),int lookup(int *const)来涨,頂層const等價(jià)
//int lookup(int&),int lookup(const int&); int lookup(int*),int lookup(const int*),如果形參是某種類型的指針或引用忌卤,則通過(guò)區(qū)分其指向的是常量對(duì)象還是非常量對(duì)象可以實(shí)現(xiàn)函數(shù)重載(底層const)扫夜。
//const_cast和重載
//shorterString,有什么特別作用嗎?當(dāng)使用非常量實(shí)參驰徊,想得到非常量的引用時(shí)笤闯,此時(shí)使用shorterString,定義2個(gè)重載函數(shù)棍厂。同時(shí)颗味,重載函數(shù)應(yīng)該避免強(qiáng)制類型轉(zhuǎn)換!
//默認(rèn)實(shí)參牺弹,調(diào)用含有默認(rèn)實(shí)參的函數(shù)浦马,可以包含該實(shí)參,也可以省略該實(shí)參张漂。
string window;
window = screen();
window = screen(255, 255, '+');
//window=screen(,,'+') 錯(cuò)誤行為晶默,在設(shè)計(jì)默認(rèn)實(shí)參函數(shù)時(shí),盡量讓使用默認(rèn)值的形參放在后面航攒,不適用默認(rèn)值的形參放在前面磺陡!
//默認(rèn)實(shí)參初始值含義?
//內(nèi)聯(lián)函數(shù)漠畜,適用于節(jié)省開(kāi)銷币他、流程直接、頻繁調(diào)用的函數(shù)
int inline_a = 3, inline_b = 5;
cout << max_numbers(inline_a, inline_b)<<endl; //等價(jià)于cout<<(a < b ? b : a)<<endl;
//constexpr函數(shù)憔狞,函數(shù)的返回類型和所有形參的類型都得是字面值類型(內(nèi)置類型蝴悉、引用、指針)瘾敢,而函數(shù)體中必須有且只有一條return語(yǔ)句拍冠。
int arr_constexpr1[arr_count(2)];
size_t i_constexpr = 2;
//int arr_constexpr2[arr_count(i_constexpr)]; arr_count返回值不為常量表達(dá)式。
//調(diào)試幫助簇抵,assert和NDEBUG
assert(3 > 2); //如果表達(dá)式為假庆杜,則輸出信息并終止程序,可以用#define語(yǔ)句定義NDEBUG語(yǔ)句正压,關(guān)閉調(diào)式狀態(tài)欣福!
//函數(shù)指針责球,指向函數(shù)而非對(duì)象
int a_func = 1, b_func = 2;
p_addb = addb; //等價(jià)于p_addb=&addb.另外可以為p_addb賦值nullptr焦履,表示沒(méi)有指向任何一個(gè)函數(shù)拓劝。
cout << addb(a_func, b_func) << endl;
cout << p_addb(a_func, b_func) << endl;
cout << (*p_addb)(a_func, b_func) << endl; //等價(jià)于上面調(diào)用語(yǔ)句
//使用函數(shù)指針作為形參, 將函數(shù)作為實(shí)參
print_addb(cout, addb);
print_addb(cout, addb,1,9);
//返回指向函數(shù)的指針
using F = int(int);
using PF = int(*)(int);
//PF f1(int),f1返回指向函數(shù)的指針
//F *f1(int),f1返回指向函數(shù)的指針
//auto f1(int)->int(*)(int),返回指向函數(shù)的指針嘉裤。
//也可以使用decltype推斷函數(shù)的類型郑临,得到形如F形式,接著聲明函數(shù)屑宠。
cin.ignore();
return 0;
}
//函數(shù)包含返回類型聲明厢洞、函數(shù)名、形參典奉、實(shí)參躺翻、函數(shù)體等等部分,另外可以對(duì)函數(shù)進(jìn)行重載卫玖。
//內(nèi)聯(lián)函數(shù)可以避免常見(jiàn)的函數(shù)調(diào)用開(kāi)銷公你!
//省略符形參是什么鬼?