宏函数,用空间换时间
//宏函数缺陷1:需要加括号
#define myAdd(x,y) ((x)*(y));
//缺陷2:即使加了括号,但也可能与预期不符合
#define myCompare(a,b) ((a)<(b)?(a):(b))
void test01(){
int a=10;
int b=20;
int ret=myCompare(++a,b);//由于宏函数的性质,++a调用了两次
cout<<ret<<endl;
}
//为了避免宏缺陷,所有有了内联函数
内联函数是个真正的函数,不会有宏函数的缺陷,但是会在必要的时候按照宏函数的模式运行
inline int myCompare2(int a,int b)
inline int myCompare2(int a,int b){return a<b?a:b;}
内联函数只是对编译器的一个建议,编译器不一定接受这种建议,并且就算不写inline,编译器也会对适合内联的函数加inline关键字
函数形参可以有默认值
int func(int a,int b=20,int c=30){
return a+b+c;
}
int main(){
cout<<func(10,30);
//如果传了参数,那么是用传入的,而不是初始化的默认值
return 0;
}
注意事项:
void func(int a,int =10){
cout<<"this is func"<<endl;
}
int main(){
func(10,1);
return 0;
}
函数名可以相同,提高代码的复用性
函数重载的满足条件:
void func(int &a){
cout<<"func(int &a)"<<endl;
}
void func(const int &a){
cout<<"func(const int &a)"<<endl;
}
void func2(int a,int b=10){
cout<<"func2(int a,int b)"<<endl;
}
void func2(int a){
cout<<"func2(int a)"<<endl;
}
int main(){
func(1);//调用const int &a
int a =10;
func(a);//调用int &a
const int b=10;
func(b);//调用const int &a
func2(1);//出现二义性。尽量避免
return 0;
}
编译器可能会对函数名进行修饰,比如
void func() _func
void func(int a) _func_int
void func(int a,char c) _func_int_char
所以可以实现函数重载
如果用C++的编译方式,可能会将函数修饰,再去调用
解决方式:
利用C语言的方式
extern "C" void show()//删掉头文件
在.h文件中加上几行代码
#ifdef __cpluscplus
extern "C"{
#endif
#ifdef __cpluscplus
}
#endif
C++面向对象的三个特性:封装、继承、多态
意义:
const double pi =3.14;
class Circle{
public:
int m_R;
double calC(){
return 2*pi*m_R;
}
};
int main(){
Circle c;
c.m_R = 10;
cout<<c.calC()<<endl;
}
public 公共权限 类内可以访问,类外也可以访问
private 私有权限 类内可以访问,类内不可以访问,不可继承
protected 保护权限 类内可以访问,类内不可以访问,可以继承
class Person{
public:
string name;
protected:
string car;
private:
string password;
public:
void init(){
name="zhang";
car="BMV";
password="123445";
}
};
int main(){
Person p;
p.name="lin";
//p.car="1";不可访问,会报错
}
默认的访问权限不同
struct默认为public
class默认为private
class Person{
public://提供接口
void set_name(string new_name){
name=new_name;
}
string get_name(){
return name;
}
void set_age(int new_age){
if(new_age<0)age=0;
else if(new_age>150)age=0;
else age=new_age;
}
int get_age(){
return age;
}
void set_lover(string lover_name){
lover=lover_name;
}
private:
string name;//可读可写
int age;//可读
string lover;//可写
};
int main(){
Person p;
p.set_name("zhang");
cout<<p.get_name()<<endl;
}
可以自己控制读写权限
可以控制写入的有效范围
class Cube{
public:
void set_L(int L){m_L=L;}
void set_W(int W){m_W=W;}
void set_H(int H){m_H=H;}
int get_L(){return m_L;}
int get_W(){return m_W;}
int get_H(){return m_H;}
int get_V(){return m_L*m_W*m_H;}
int get_S(){return 2*(m_L*m_W+m_L*m_H+m_W*m_H);}
bool is_equal(Cube &a){
if(m_L!=a.get_L())return false;
if(m_W!=a.get_W())return false;
if(m_H!=a.get_H())return false;
return true;
}
private:
int m_L;
int m_W;
int m_H;
};
bool isSame(Cube &a,Cube &b){
if(b.get_L()!=a.get_L())return false;
if(b.get_W()!=a.get_W())return false;
if(b.get_H()!=a.get_H())return false;
return true;
}
int main(){
Cube a,b;
a.set_L(10);
a.set_W(10);
a.set_H(10);
b.set_L(10);
b.set_W(10);
b.set_H(10);
cout<<isSame(a,b)<<endl;
cout<<a.is_equal(b)<<endl;
}
如果自己不写,编译器会提供,只是是空的
class Person{
public:
Person(){
cout<<"use"<<endl;
}
~Person(){
cout<<"use"<<endl;
}
private:
string name;
int age;
string lover;
};
int main(){
Person p;
}
按参数分:
int main(){
//括号法
Person p;//Person p()错误
Person p1(10);
Person p2(p1);
//显示法
Person p;
Person p1=Person(10);
Person p2=Person(p2);//对于右侧的匿名对象,改行结束后,内存会被释放
//隐式转换法
Person p4 = 10;//Person p1=Person(10);
}
注意事项:
调用默认构造时注意不要带括号,因为编译器会把加了括号的Person p()当做函数声明
不要利用拷贝函数去初始化一个匿名对象
void doWork(Person p){}
Person doWork2(){
Person pp;
return pp;
}
int main(){
Person p1(10);
Person P2(p1);
Person p;
doWork(p);//在将实参传给形参时会用拷贝构造函数构造
doWork();//将pp用构造函数拷贝再返回
}
#####构造函数调用规则
默认情况下,只要写了class就会提供
默认构造函数,默认拷贝构造函数,默认析构函数
如果用户定义了有参构造函数,那就不提供无参构造,但提供拷贝构造
如果用户定义了拷贝构造函数,不提供其他构造函数
浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区申请空间,进行拷贝操作(new delete)
如果利用编译器的拷贝构造函数,会做浅拷贝操作
析构时先进后出,重复析构,则会重复释放
浅拷贝造成了重复释放,利用深拷贝解决
class Person{
public:
Person(){}
Person(int a,int h){
age=a;
height= new int(h);
}
Person(const Person &p){
age=p.age;
//height = p.height;//默认的浅拷贝
height=new int(*p.height);//深拷贝
}
~Person(){
//将堆区的数据释放
if(height!=nullptr){
delete height;
height=nullptr;
}
}
int age;
int *height;
};
int main(){
Person p1(10,100);
Person p2(p1);
}
Person():age(0),height(80){}
Person(int a,nt b):age(a),height(b){}
类中的成员可以使另一个类的对象,构造的顺序
class A{
};
class B{
A a;
};
//先构造A再构造B,先析构B再析构A
防止隐式法构造,括号法和显示法
this指针指向被调用的成员函数所属的对象
class Person{
public:
int age;
Person(int age){
//age=age;//错误,变量名冲突
this->age=age;
}
Person& PersonAddAge(Person &p){//如果用值的方式返回,就不是返回到p2,而是创建了一个新的对象
this->age+=p.age;
return *this;
}
};
int main(){
Person p1(10);
Person p2(0);
//p2.PersonAddAge(p1);
p2.PersonAddAge(p1).PersonAddAge(p1);
cout<<p2.age<<endl;
}
class Person{
public:
void showClassName(){
cout<<"this is person class"<<endl;
}
void showPersonAge(){
if(this==nullptr)return;
cout<<this->age<<endl;//因为传入的是空指针,访问属性所以报错
}
int age;
};
int main(){
Person* p = nullptr;
p->showClassName();
p->showPersonAge();
}
左移运算符
class Person{
friend ostream& operator << (ostream &cout,Person &p);
public:
Person(int a,int b):A(a),B(b){}
private:
int A;
int B;
//成员函数重载,一般不用,cout再右边
};
ostream& operator << (ostream &cout,Person &p){
cout<<p.A<<" "<<p.B<<endl;
}
int main(){
Person p(10,10);
cout<<p;
}
因篇幅问题不能全部显示,请点此查看更多更全内容