1.静态成员变量和静态成员函数
所谓的静态成员变量和静态成员函数就是对类中的成员变量和成员函数前面加上关键字static
static int m_age;
static void func()
{
//m_a = 10;
m_age = 100;
cout << "func函数调用" << endl;
}
静态成员变量需要在类内声明,在类外进行初始化,并且它也是具有权限的;而静态成员函数不可以访问普通的成员变量,可以访问静态成员变量,也是具有权限(注意:静态成员变量在编译阶段就分配内存了)
class Person
{
public:
Person()
{
}
static int m_age;
static void func()
{
//m_a = 10;
m_age = 100;
cout << "func函数调用" << endl;
}
//普通成员函数,可以访问普通成员变量,也可以访问静态成员变量
void myfunc()
{
m_a = 100;
m_age = 100;
}
int m_a;
private:
static int m_other;//私有权限,在类外不能访问
static void func2()
{
cout << "func2函数调用" << endl;
}
};
int Person::m_age = 0;//类外初始化实现
int Person::m_other = 10;//类外初始化实现
静态成员变量的作用是共享数据,既可以通过对象来访问属性,也能够通过类名来访问属性(静态成员函数同上)
//通过对象来访问属性
Person p1;
p1.m_age = 10;
Person p2;
p2.m_age = 20;
cout << "p1 = " << p1.m_age << endl;
cout << "p2 = " << p2.m_age << endl;
//共享数据
//2.通过类名访问属性
cout << "通过类名访问age" << Person::m_age << endl;
2.单例模式案例
2.1 总统案例
需求:单例模式是为了创建类中的对象,并且保证只有一个对象实例,
即对象只能有一个总统
1.先创立一个总统类
class Chairman
{
Chairman()
{
//cout << "创建国家主席" << endl;
}
};
在测试函数1中可以发现可以创建对个对象,所以要将构造函数私有化,防止对象乱建
void test1()
{
Chairman c1;
Chairman* c2 = new Chairman;
Chairman* c3 = new Chairman;
}
2.将构造函数私有化,并设置静态成员变量singleman权限公开,在类外初始化
class Chairman
{
private:
Chairman()
{
//cout << "创建国家主席" << endl;
}
public:
static Chairman* singleman;
};
Chairman* Chairman::singleman = new Chairman;
在测试函数2中可以看到建立的对象cm和cm2都是对singleman属性的共享,但是并不能阻止它将其修改为空
void test2()
{
Chairman * cm = Chairman::singleman;
Chairman * cm2 = Chairman::singleman;
Chairman::singleman = NULL;
}
3.为了防止将singleman乱修改,将其设置为私有化,并为其提供对外接口静态成员函数getInstance()
class Chairman
{
private:
Chairman()
{
//cout << "创建国家主席" << endl;
}
static Chairman* singleman;
public:
static Chairman* getInstance()
{
return singleman;
}
};
Chairman* Chairman::singleman = new Chairman;
此时在测试函数3中可以看到创建的两个对象是相同的,但是cm3调用了默认的拷贝构造函数,又创建了一个对象,所以应将拷贝构造函数私有化
void test3()
{
Chairman* cm1 = Chairman::getInsatnce();
Chairman* cm2 = Chairman::getInsatnce();
if (cm1 == cm2)
{
cout << "cm1与cm2相同" << endl;
}
else
{
cout << "cm1与cm2不相同" << endl;
}
Chairman* cm3 = new Chairman(*cm2);
if (cm3 == cm2)
{
cout << "cm3与cm2相同" << endl;
}
else
{
cout << "cm3与cm2不相同" << endl;
}
}
最终类的构造
class Chairman
{
//构造函数私有化
private:
Chairman()
{
//cout << "创建国家主席" << endl;
}
//拷贝构造私有化
Chairman(const Chairman& c)
{
}
static Chairman* singleman;
public:
static Chairman* getInsatnce()
{
return singleman;
}
};
Chairman* Chairman::singleman = new Chairman;
2.2 打印机案例
class Printer
{
private:
Printer()
{
m_count = 0;
}
Printer(const Printer & p)
{}
static Printer* singleprinter;
int m_count;//记录打印的次数
public:
static Printer* getInstance()
{
return singleprinter;
}
void printTest(string text)
{
cout << text << endl;
m_count++;
//cout << "打印机使用了次数为:" << m_count << endl;
}
int getci()
{
cout << "打印机使用了次数为:" << m_count << endl;
return 0;
}
};
Printer* Printer::singleprinter = new Printer;
由此总结单例模式的结构:
1.将默认构造和拷贝构造私有化
2.内部维护一个对象指针
3.私有化唯一指针
4.对外提供 getInstance方法来访问这个指针
5.保证类中只能实例化唯一一个对象
3.成员变量和成员函数分开存储
当建立一个空类时,空类的大小为1,每一个实例的对象都有独一无二的地址,char维护这个地址
class Person
{
public:
int m_A;//非静态成员变量,属于对象身上,此时类的大小为4
void func() {};//非静态成员函数不属于对象身上,此时类的大小为4
static int m_B;//静态成员变量,不属于对象身上,此时类的大小为4
static void func2() {};//静态成员函数,不属于对象身上,此时类的大小为4
double m_C;//为了对齐,选择最大的那个,此时类的大小为8+8=16
};
//结论:只有非静态成员变量属于对象
4.this指针的使用
this指针指向被调用的成员函数所属的对象
class Person
{
public:
Person(int age)//this可以解决命名冲突
{
this->age = age;
}
//对比年龄
void compareAge(Person& p)
{
if (this->age == p.age)
{
cout << "年龄相等" << endl;
}
else
{
cout << "年龄不等" << endl;
}
}
//年龄相加
Person& Plusage(Person& p)
{
this->age += p.age;
return *this; //*this指向对象本体
}
int age;
};
void test()
{
Person p1(102);
cout << "p1的年龄:" << p1.age << endl;
Person p2(102);
p1.compareAge(p2);
p1.Plusage(p2).Plusage(p2).Plusage(p2);//链式编程 408
cout << "p1的年龄:" << p1.age << endl;
}
只有非静态的成员函数才有this指针
如果成员函数没有用到this,那么空指针可以直接访问
如果成员函数用的this指针,就要注意,可以加if判断,如果this为NULL就return
class Person
{
public:
void show()
{
cout << "Person show" << endl;
}
void showAge()
{
if (this == NULL)
{
return;
}
cout << m_Age << endl;
}
int m_Age;
};
void test()
{
Person* p = NULL;
p->show();
p->showAge();
}
5.const修饰成员函数和成员变量
//在构造函数中修改属性,this永远指向本体
//const Person * const this
class Person
{
public:
Person()
{
this->m_A = 0;
this->m_B = 0;
}
在函数后面加上const关键字就变成了常函数
void showInfo() const //常函数,不允许修改指针指向的值,修饰是this指针const Type * const this
{
//this->m_A = 1000;
this->m_B = 106;
//const Person * const this
cout << "m_A = " << this->m_A << endl;
cout << "m_B = " << this->m_B << endl;
}
void show2()const
{
//m_A = 100;
}
int m_A;
mutable int m_B;//在常函数中如果想修改,就在成员属性前面加上关键字mutable
};
void test()
{
Person p1;
p1.showInfo();
//常对象,不允许修改属性
const Person p2;
//cout << p2.m_A << endl;
p2.show2();
//常对象不可以调用普通的成员函数,但是可以调用常函数
}
6.友元函数
友元函数是一种特权函数,c++允许这个特权函数访问私有成员
全局函数做友元函数
先建立一个类Building,一个私有属性卧室,一个公开属性客厅,为了让全局函数访问类的私有属性,就在类中将全局函数变为友元函数
class Building
{
//让全局函数变为友元函数
friend void goodGay(Building* b);
public:
Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}
//客厅 卧室
public:
string m_SittingRoom;
private:
string m_BedRoom;
};
//全局函数
void goodGay(Building * b)
{
cout << "好朋友正在访问" << b->m_SittingRoom << endl;
cout << "好朋友正在访问" << b->m_BedRoom << endl;
}
类做友元类
class Building;//先声明,防止报错
class goodGay
{
public:
goodGay();//类内构造函数声明
void visit();//类内成员函数声明
private:
Building* b;
};
class Building
{
//让goodGay这个类作为Building类的好朋友,可以访问Building的成员属性
friend class goodGay;
public:
Building();//类内构造函数声明
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
};
goodGay::goodGay()//类外实现构造函数,goodGay类的构造函数,创建Building对象
{
b = new Building;
}
void goodGay::visit()//类外实现成员函数,注意返回值要与声明一致
{
cout << "好朋友正在访问:" << this->b->m_SittingRoom << endl;
cout << "好朋友正在访问:" << this->b->m_BedRoom << endl;
}
Building::Building()//类外实现Building的构造函数,进行参数初始化
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}
void test()
{
goodGay g;//调用goodGay构造函数
g.visit();
}
成员函数做友元函数
//只让 visit1可以访问Building的私有属性 visit2 不可以访问私有属性
class Building;
class goodGay
{
public:
goodGay();
void visit1();
void visit2();
private:
Building* building;
};
class Building
{
//让成员函数 visit1作为友元函数
friend void goodGay::visit1();
public:
Building();
public:
string m_SittingRoom; //客厅
private:
string m_BedRoom; //卧室
};
goodGay::goodGay()
{
building = new Building;
}
void goodGay::visit1()
{
cout << "好朋友正在访问: " << this->building->m_SittingRoom << endl;
cout << "好朋友正在访问: " << this->building->m_BedRoom << endl;
}
void goodGay::visit2()
{
cout << "好朋友正在访问: " << this->building->m_SittingRoom << endl;
//cout << "好朋友正在访问: " << this->building->m_BedRoom << endl;
}
Building::Building()
{
this->m_SittingRoom = "客厅";
this->m_BedRoom = "卧室";
}
总结:
全局函数写到类中做声明并且最前面写关键字friend
friend关键字只出现在声明处
类变为友元类:friend class 类名
友元类是单向的,不可传递的
成员函数变为友元函数:friend void goodGay::visit();
其他类、类成员函数、全局函数都可声明为友元
友元函数不是类的成员,不带this指针
友元函数可访问对象任意成员属性,包括私有属性