3.8,类对象作为类成员
C++类中的成员可以是另一个类的对象,我们称该成员为对象成员。
如果C对象中有B对象那么他们的析构函数和构造函数的顺序是什么。
构造函数的顺序是先进行B构造在进行C构造,
析构函数的顺序是先进行C析构在进行B析构。
#include<iostream>
using namespace std;
class phone
{
public:
phone(string name):m_name(name)
{
cout<<"this is construction about phone"<<endl;
}
~phone()
{
cout<<"this is destruction about phone"<<endl;
}
public:
string m_name;
};
class person
{
public:
person(int b,string c):m_Age(b),m_c(c)
{
cout<<"this is construction about person"<<endl;
}
~person()
{
cout<<"this is destruction about person"<<endl;
}
public:
int m_Age;
phone m_c;
};
int main()
{
person b(50,"meizu");
return 0;
}
3.9静态成员
静态成员分为两个静态成员变量和静态成员函数。
a,静态成员变量
1,所有对象共享同一份数据
2,在编译阶段分配内存
3,类内声明,在类外初始化
b,静态成员函数
1,所有对象共享同一个函数
2,静态成员函数只能访问静态成员变量
#include<iostream>
using namespace std;
class person
{
public:
static void test(int age)
{
m_age+=age;
cout<<m_age<<endl;
cout<<"this is staticFunc"<<endl;
}
public:
static int m_age;
int m;
};
int person::m_age=100;
int main()
{
person b;
b.test(10);
cout<<b.m_age<<endl;
person::test(1000);
cout<<person::m_age<<endl;
return 0;
}
4对象模型和this指针
4.1成员变量和成员函数分开存储
在C++中,类内的成员变量和成员函数分开存储只有非静态成员变量才属于类的对象上,其他都不属于。
注意:空对象编译器会给它分配1字节的空间,成员函数也不属于对象。
4.2,this指针
this指针的作用
1,当形参和成员变量同名时,可以用this指针来区分。
2,在类的非静态成员函数中返回对象本身,可使用return *this。
this指针是一个指针常量
#include<iostream>
using namespace std;
class person
{
public:
person(int age)
{
this->age=age;//当形参和成员变量同名时,可以用this指针来区分。
}
person &addtoadd(person a)
{
this->age+=a.age;
return *this;//在类的非静态成员函数中返回对象本身,可使用return *this。
}
public:
int age;
};
int main()
{
person b(10);
person a(10);
cout<<"age="<<b.age<<endl;
b.addtoadd(a).addtoadd(a).addtoadd(a).addtoadd(a);
cout<<"age="<<b.age<<endl;
return 0;
}
4.3,空指针访问成员函数
空指针访问成员函数需要保证函数的健壮性,加以判断
eg:
#include<iostream>
using namespace std;
class person
{
public:
void showname()
{
cout<<"all time no"<<endl;
}
void showage()
{
if(this==NULL)
{
return;
}
cout<<"age:"<<this->m_Age<<endl;
}
public:
int m_Age;
};
void test()
{
person *b=NULL;
b->showname();
b->showage();
}
int main()
{
test();
return 0;
}
4.4,const修饰成员函数
常函数
a,成员函数后加const后我们称为这个函数为
b,常函数不可以修改成员属性,成员属性前加关键字mutable后,在常函数中仍然可修改
常对象
a,声明对象能加const称该对象为常对象
b,常对象只能调用常函数
eg:
#include<iostream>
using namespace std;
class person
{
public:
void showage() const
{
this->age =100;
cout<<"age"<<age<<endl;
}
public:
mutable int age;
};
int main()
{
person b;
b.showage();
const person a;
a.showage();
return 0;
}
5.1,友元
在程序里,有些私有属性也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术。友元的目的就是让一个函数或者类访问另一个类中的私有成员。
友元关键字:friend
友元的三种实现
a,全局函数做友元
b,类做友元
c,成员函数做友元
注意:最好使用友元类
#include<iostream>
#include<string>
using namespace std;
class building
{
friend class person;//类做友元
friend void test();//成员函数做友元
public:
/*building()
{
m_age=18;
m_name="one";
}*/
building();
private:
int m_age;
string m_name;
};
class person
{
friend class building;
friend void test();
public:
/*person()
{
b= new building;
}
void show()
{
cout<<"name:"<<person::b->m_name<<endl;
cout<<"age"<<person::b->m_age<<endl;
}*/
void show();
person();
private:
building *b;
};
building::building()
{
m_age = 18;
m_name = "one";
}
person::person()
{
b = new building;
}
void person::show()
{
cout << "name:" << person::b->m_name << endl;
cout << "age" << person::b->m_age << endl;
}
void test()
{
person c;
cout << "name:" << c.b->m_name << endl;
cout << "age" << c.b->m_age << endl;
}
int main()
{
// test();
person c;
c.show();
return 0;
}
成员函数做友元
#include<iostream>
#include<string>
using namespace std;
class phone;//注意这里要声明成员类,否则编译器不认识
class person
{
public:
void show();
person();
phone* m;
};
class phone
{
friend void person::show();
public:
phone();
private:
string m_name;
};
person::person()
{
m = new phone;
}
phone::phone()
{
m_name = "one";
}
void person::show()
{
cout << m->m_name << endl;
}
int main()
{
person b;
b.show();
return 0;
}
6,运算符重载
自己理解就是使原来的的运算符功能增加。
有两种运算符重载方式:
1,成员函数重载。2,全局函数重载
a,加号运算符重载
#include<iostream>
using namespace std;
class person
{
public:
person operator+(person &a)
{
person temp;
temp.a_age = this->a_age+a.a_age;
temp.b_age = this->b_age+a.b_age;
return temp;
}
public:
int a_age;
int b_age;
};
/*person operator+(person &a,person &b)
{
person temp;
temp.a_age = b.a_age+a.a_age;
temp.b_age = b.b_age+a.b_age;
return temp;
}*/
int main()
{
person a;
a.a_age=100;
a.b_age=90;
person b;
b.a_age=100;
b.b_age=90;
person c;
// c = operator+(a,b);
c = a.operator+(b);
cout<<"c.a_age= "<<c.a_age<<"c.b_age="<<c.b_age<<endl;
return 0;
}
b,左移运算符重载
这个不要用成员函数重载因为成员函数重载会使cout在右边
#include<iostream>
using namespace std;
class person
{
public:
friend ostream &operator<<(ostream &cout,person &b);
person()
{
m_a=10;
m_b=10;
}
private:
int m_a;
int m_b;
};
ostream &operator<<(ostream &cout,person &b)
{
cout<<"b.m_a"<<b.m_a<<"b.m.b"<<b.m_b;
return cout;
}
int main()
{
person b;
cout<<b<<endl;;
return 0;
}
c,a++,++a,–a,a++运算符重载(此代码不能在linuxVIM下编译成功但在vs下能成功)
#include<iostream>
using namespace std;
class person
{
friend ostream &operator<<(ostream &cout, person &a);
public:
person()
{
m_age = 10;
}
person &operator--()
{
--m_age;
return *this;
}
person operator--(int)
{
person temp;
temp = *this;
m_age--;
return temp;
}
private:
int m_age;
};
ostream &operator<<(ostream &cout, person &a)
{
cout << "m_age" << a.m_age;
return cout;
}
void test()
{
person a;
cout << a--<< endl;
cout << a << endl;
}
int main()
{
test();
system("pause");
return 0;
}
#include<iostream>
using namespace std;
class person
{
friend ostream &operator<<(ostream &cout,person &a);
public:
person()
{
m_age=10;
}
person &operator++()
{
++m_age;
return *this;
}
person operator++(int)
{
person temp;
temp = *this;
m_age++;
return temp;
}
private:
int m_age;
};
ostream &operator<<(ostream &cout,person &a)
{
cout<<"m_age"<<a.m_age;
return cout;
}
void test()
{
person a;
cout<<a<<endl;
cout<<a++<<endl;
}
int main()
{
test();
return 0;
}
d,比较运算符重载==and!=
#include<iostream>
#include<string>
using namespace std;
class person
{
public:
person(string m_Name,int m_Age)
{
this->m_Name = m_Name;
this->m_Age = m_Age;
}
bool operator==(person &p)
{
if(this->m_Name==p.m_Name&&this->m_Age == p.m_Age)
{
return true;
}
return false;
}
bool operator!=(person &p)
{
if(this->m_Name!=p.m_Name && this->m_Age != p.m_Age)
{
return false;
}
return true;
}
public:
string m_Name;
int m_Age;
};
void test01()
{
person a("tom",18);
person b("jk",18);
if(a==b)
{
cout<<"same"<<endl;
}
else{
cout<<"different"<<endl;
}
}
void test02()
{
person a("tom",18);
person b("jk",18);
if(a!=b)
{
cout<<"different"<<endl;
}
else{
cout<<"same"<<endl;
}
}
int main()
{
test01();
test02();
return 0;
}
e,赋值运算符=
运算符重载最重要的重载里面涉及到深拷贝与浅拷贝的问题,当你把一个对象赋给另外一个对象时,类成员如果是自己开辟的成员的值就会出现析构函数中对一个地址释放两次的非法操作。
注意类中一旦出现了自己开辟的空间一定要自己写拷贝构造以及析构函数。
#include<iostream>
using namespace std;
class person
{
public:
person &operator=(person &p)
{
if(m_age==NULL)
{
delete m_age;
m_age=NULL;
}
m_age = new int(*p.m_age);
return *this;
}
person()
{
}
person(int age)
{
m_age = new int(age);
}
person(const person &p)
{
m_age = new int(*(p.m_age));
}
~person()
{
if(m_age==NULL)
{
delete m_age;
m_age=NULL;
}
}
public:
int *m_age;
};
int main()
{
person b(18);
person a;
person c;
c=a=b;
cout<<"a"<<*a.m_age<<endl;
cout<<"b"<<*b.m_age<<endl;
return 0;
}
f,函数运算符重载()
也叫仿函数,没有固定的写法运用时最灵活在stl容器中经常用到。
#include<iostream>
#include<string>
using namespace std;
class myprint
{
public:
void operator()(string test)
{
cout<<test<<endl;
}
};
class myAdd
{
public:
int operator()(int min,int max)
{
return min+max;
}
};
void test()
{
myprint b;
b("you are a good boy");
}
void test01()
{
myAdd a;
cout<<a(5,3)<<endl;
cout<<myAdd()(5,4)<<endl;
}
int main()
{
test01();
return 0;
}