inthalf(intx){cout<<"1"<<endl;returnx/2;}doublehalf(doublex){cout<<"2"<<endl;returnx/2;}inthalf(intx,intdivisor=2)// default parameter values{cout<<"3"<<endlreturnx/divisor;}half(3);// use version 1, return 1 half(3.0);// use version 2, return 1.5half(3,3);// use version 3, return 1
intnumOne={12.5};// or int numOne{12.5};/*Error Message:错误:narrowing conversion of ‘1.25e+1’ from ‘double’ to ‘int’ [-Wnarrowing] | int num = {12.5};*/
花括号的意义在于更好的安全性
除了上述使用方法外,花括号在 C++ 赋初值中无处不在,例如下列代码实现对 map 和 Vector 的 Uniform Initialization:
// A. static_cast 可以用在基类和子类的互相转换,无编译错误,但是实际运行时有可能出错structU{};structV:publicU{};structW:publicU{};intmain(){U*p=newV;W*q=static_cast<W*>(p);returnq==nullptr;}// B. dynamic_cast 只能用在基类和子类是多态的时候,即基类一定要有 virtual 函数。// 但是实际上只要 dynamic_cast<target>(expression) 中 expression 是多态类型即可,只不过此例中 W 和 U 无继承关系,会返回空指针structU{virtualvoidfoo(){}};structV:publicU{};structW{};intmain(){U*p=newV;W*q=dynamic_cast<W*>(p);returnq==nullptr;}// C. 理由同上,但是此例不返回空指针structU{virtualvoidfoo(){}};structV:publicU{};structW:publicU{};intmain(){U*p=newV;W*q=dynamic_cast<W*>(p);returnq==nullptr;}// D. static_cast 不允许用于转换两个不相关的指针(除了 void*)structU{};structV:publicU{};structW{};intmain(){U*p=newV;W*q=static_cast<W*>(p);returnq==nullptr;}
#include<iostream>usingnamespacestd;structStudent{stringname;stringstate;intage;};voidprintStudentInfo(Students){cout<<s.name<<" from "<<s.state;cout<<" ("<<s.age<<")"<<endl;}intmain(void){Students={"Nimisora","CS",17};printStudentInfo(s);}
与 C 语言略有不同的是,C++的结构变量可以直接使用结构体名声明定义,而C需要加上 struct 。
std::pair<bool,Student>lookupStudent(stringname){Studentblank;if(notFound(name))returnstd::make_pair(false,blank);Studentresult=getStudentWithName(name);returnstd::make_pair(true,result);}std::pair<bool,Student>output=lookupStudent("Inuisana");// auto output = lookupStudent("Inuisana") // More Neat!
#include<cmath> // for sqrt#include<iostream> // to print#include<utility> // for pairsstd::pair<bool,std::pair<int,int>>solveQuadratic(inta,intb,intc){autodiscriminant=b*b-4*a*c;if(discriminant<0)return{false,{0,0}};introot1=(-b+sqrt(discriminant))/(2*a);introot2=(-b-sqrt(discriminant))/(2*a);return{true,{root1,root2}};}intmain(){autoresult=solveQuadratic(1,-3,2);if(result.first)std::cout<<"Root 1: "<<result.second.first<<std::endl<<"Root 2: "<<result.second.second<<std::endl;elsestd::cout<<"No real roots"<<std::endl;}
inta[]={53,54,55};int*constp=a;// p is const*p=20;// OKp++;// ERRORconstint*p=a;// (*p) is const*p=20;// ERROR!p++;// OKintconst*p=a;// (*p) is const// 与上一个完全等价
#include<iostream>#include<sstream>intmain(){std::stringinitial_quote="I hate python, but I love C++";// create a stringstream object with initial valuestd::stringstreamss;ss<<initial_quote;// or you can try:// std::stringstream ss(initial_quote);// data destinationstd::stringfirst,second,third,quote;ss>>first>>second>>third>>quote;std::cout<<first<<" "<<second<<" "<<third<<" "<<quote<<std::endl;}
ss>>first>>second>>third;std::getline(ss,quote);std::cout<<first<<" "<<second<<" "<<third<<" "<<quote<<std::endl;/*Output:I hate python, but I love C++---------------------------------If we use: std::getline(ss, quote, 'C');Then the output: I hate python, but I love*/
#include<fstream>intmain(){// if `output.txt` not exit, the program will touch it.std::ofstreamofs("output.txt");if(ofs.is_open())ofs<<"Hello, CS106L"<<"\n";ofs.close();// bad tryofs<<"this will not get written";// ios::app: 表示添加数据,而不是覆盖数据ofs.open("output.txt",std::ios::app);ofs<<"It's open again!";return0;}/*output.txt:Hello, CS106LIt's open again!*/
intinputFileStreamExample(){std::ifstreamifs("output.txt");if(ifs.is_open()){std::stringline;std::getline(ifs,line);std::cout<<"Read from the file: "<<line<<"\n";}if(ifs.is_open()){std::stringlin2;std::getline(ifs,lin2);std::cout<<"Read from the file: "<<lin2<<"\n";}return0;}/*Output:Read from the file: Hello, CS106LRead from the file: It's open again!*/
istream&operator>>(istream&is,T&obj){// specific code to read objreturnis;}ostream&operator<<(ostream&os,constT&obj){// specific code to write objreturnos;}cin>>a>>b>>c;// ((cin >> a) >> b) >> c;cout<<a<<b<<c;// ((cout << a) << b) << c;
#include<vector>#include<iostream>intmain(void){// create a vector object that holds integersstd::vector<int>v0;// empty vectorstd::vector<int>v1(5);// 5 integers, all initialized to 0std::vector<int>v2(5,2);// 5 integers, all initialized to 2std::vector<int>v3={1,2,3,4,5};// 5 integers, initialized to 1, 2, 3, 4, 5// use push_back to add elements to the end of the vectorv0.push_back(1);v0.push_back(2);std::cout<<v0[1]<<"\n";// or you can use v0.at(1)// use erase to remove elements from the vectorv3.erase(v3.begin()+1);// remove the second element// use size() to get the number of elements in the vectorintsize=v1.size();// use iterator to access elements in the vectorfor(autoit=v3.begin();it!=v3.end();++it)std::cout<<*it<<" ";// use range-based for loop to access elements in the vectorfor(inti:v3)std::cout<<i<<" ";// use clear to remove all elements from the vectorv3.clear();}
classS{mutablebool_is_cached=false;mutableint_cache;public:intf()const{if(!_is_cached){/* some very, very expensive operation */_is_cached=true;_cache=42;}return_cache;}};
#include<iostream>#include<string>template<typenameT>// <typename T=int> => define a default typeTconst&max(Tconst&a,Tconst&b){returna<b?b:a;}intmain(){inta=7,b=42;std::cout<<"max(a, b): "<<max(a,b)<<std::endl;// or you can call max<int>(a, b)doublex=7.1,y=42.2;std::cout<<"max(x, y): "<<max(x,y)<<std::endl;// or you can call max<double>(x, y)// max(a, x); // ERROR!return0;}
template<typenameT>conceptAddaptable=requires(Ta,Tb){a+b;};// if a+b can be compile, then `add` worktemplate<typenameT>requiresAddaptable<T>Tadd(Ta,Tb){returna+b;}template<AddaptableT>// this shorthand also OK!Tadd(Ta,Tb){returna+b;}
// lec8.hhtemplate<typenameT>// also <class T>classContainer{public:Container(Tval);TgetVal();private:T_val;};// ====================================// lec8.cpp#include"lec8.hh"template<typenameT>// also <class T>Container<T>::Container(Tval){this->_val=val;}template<typenameT>// also <class T>TContainer<T>::getVal(){return_val;}intmain(){Container<int>intContainer(7);Container<std::string>stringContainer("Hello, world!");return0;}
// .hhclassarr{public:arr(intsize);int&findItem(intitem);constint&findItem(intitem)const;private:std::vector<int>_arr;int_size;};// ====================================// .cppint&arr::findItem(intitem){for(auto&elem:_arr)if(elem==item)returnelem;throwstd::out_of_range("Item not found");}// define a const versionconstint&arr::findItem(intitem)const{returnconst_cast<arr&>(*this).findItem(item);}
// user.h#include<set>#include<string>classUser{public:// constructorUser(){this->name="";};User(std::stringname);// getter functionsstd::stringgetName()const;std::set<User>&getFriends();conststd::set<User>&getFriends()const;// setter functionsvoidsetName(std::stringname);// operator overloadbooloperator<(constUser&b)const;// 能加 const 就加,不然报错voidoperator+(User&b);private:std::stringname;std::set<User>friends;};// =============================================// main.cpp#include<iostream>#include"User.h"voidUser::operator+(User&b){this->friends.insert(b);b.friends.insert(*this);}boolUser::operator<(constUser&b)const{returnthis->name<b.name;}voidprintFriends(constUser&user){std::cout<<user.getName()<<" is friends with: "<<std::endl;for(auto&user:user.getFriends()){std::cout<<" "<<user.getName()<<std::endl;}}intmain(){// create a bunch of usersUseralice("Alice");Userbob("Bob");Usercharlie("Charlie");Userdave("Dave");UserInuisana;Inuisana.setName("Inuisana");// make them friendsalice+bob;alice+charlie;dave+bob;charlie+dave;alice+Inuisana;// print out their friendsprintFriends(alice);printFriends(bob);printFriends(charlie);printFriends(dave);return0;}/*Output:Alice is friends with: Bob Charlie InuisanaBob is friends with: Alice DaveCharlie is friends with: Alice DaveDave is friends with: Bob Charlie*/
User&operator+(User&fir,User&sec){fir.friends.insert(sec);sec.friends.insert(fir);returnfir;}/*In this case, you can: alice + bob; // operator+(alice, bob) alice = alice + bob;ALl OK!全局 operator 往往还需要在类中设置为 friend,如:friend User& operator+(User& fir, User& sec);*/
原因是 Member Function 中 this 是作为一个隐式的参数传递的,因此也相当于两个参数
#include<cstring>#include<iostream>usingnamespacestd;classStr{charm_s[10];char*m_p;public:Str(char*s){strcpy(m_s,s);m_p=m_s;}operatorchar*(){returnm_p;}char*operator++(){return++m_p;}charoperator[](inti){returnm_s[i];}};intmain(){Strs("hello");cout<<*s<<endl;// prints "h", 这里先将 s 转换为 m_p,再解引用 *s 得到第一个值++s;cout<<s[0]<<endl;// prints 'h'cout<<*s<<endl;// prints 'e'return0;}