一.static成员
1.概念:声明为static的类成员成为类的静态成员。
用static修饰的成员变量称为静态成员变量,
用static修饰的成员函数称为静态成员函数。
class Test {
public:
//Test():m_a(0){}
Test():m_b(0){
}
//静态函数没有this指针
static void fun() {//静态函数只能调用静态成员,不能调用普通成员
m_a = 0;
//show();不能调用
}
void show() {//普通函数能够调用普通成员和静态成员
m_b = 0;
m_a = 0;
fun();
}
private:
static int m_a;//静态成员不能通过参数列表的形式在类体内进行初始化,只能在类外进行初始化
int m_b;
};
int Test::m_a = 0;//初始化时使用类名+作用域解析符
void main() {
Test t;
}
2.特性:
- 静态成员为所有类对象共享,不属于某个具体的实例
- 静态成员变量必须在类外定义,定义时不添加static关键字
- 类静态成员即可用类名::静态成员或者对象.静态成员来访问
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
- 静态成员也有public、protected、private 3中访问级别,也可以具有返回值
二.友元
友元分为:友元函数和友元类
1.友元函数:可以将一个和类无关的函数,使其类对象能够直接访问类中的私有成员
class Test {
friend void fun(const Test &t);
friend ostream& operator<<(ostream& out, const Test &d);
public:
Test(int data = 0) {
m_data = data;
}
int GetData()const {
return m_data;
}
private:
int m_data;
};
void fun(const Test &t) {
int data = t.m_data;//使void fun()函数成为友元函数就可直接访问m_data
}
ostream& operator<<(ostream& out, const Test &d) {
out << d.m_data;
return out;
}
int main() {
Test t(10);
fun(t);
cout << "t = " << t << endl;
return 0;
}
注:因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以我们要将operator<<重载成全局函数。但是这样的话,又会导致类外没办法访问成员,那么这里就需要友元来解决。
友元函数可以直接访问类的私有成员,它是定义在类外的普通函数,不属于任何类,但需在类的内部声明,声明时需要加friend关键字
说明:
- 友元函数可以访问类的私有成员和保护成员,但不是类的成员函数
- 友元函数不能用const修饰
- 友元函数可以在类的任何地方声明,不受类访问限定符限制
- 一个函数可以是多个类的友元函数
class A {
friend void fun(const Test &t, const A &a);
private:
int m_a = 0;
};
class Test {
friend void fun(const Test &t, const A &a);
friend ostream& operator<<(ostream &out, const Test &t);
friend istream& operator>>(istream &in, Test &t);
public:
Test(int data = 0) :m_data(data) {}
~Test() {}
private:
int m_data;
};
void fun(const Test &t, const A &a) {//一个函数可以是多个类的友元函数
cout << "data = " << t.m_data << endl;
}
ostream& operator<<(ostream &out, const Test &t) {
out << t.m_data;
return out;
}
istream& operator>>(istream &in, Test &t) {
in >> t.m_data;
return in;
}
void main() {
Test t;
A a;
cin >> t;
cout << "t = " << t << endl;
}
2.友元类:友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员
特性:
- 友元关系是单向的,不具有交换性
class List;//前置声明
class ListNode {
friend class List;//友元类
public:
ListNode():m_data(0),m_next(nullptr)
{}
~ListNode()
{}
public:
void fun() {
List t;
//友元关系是单向的,不具有交换性
cout << t.m_head << endl;//t使用了未定义的class"List"
}
private:
int m_data;
ListNode *m_next;
};
class List {
public:
List() :m_head(nullptr)
{}
~List()
{}
public:
void push_front(int v) {
ListNode *s = (ListNode*)malloc(sizeof(ListNode));
assert(s != NULL);
s->m_data = v;
s->m_next = nullptr;
s->m_next = m_head;
m_head = s;
}
void show_list() const {
ListNode *p = m_head;
while (p != nullptr) {
cout << p->m_data << "-->";
p = p->m_next;
}
cout << "Over." << endl;
}
private:
ListNode *m_head;
};
int main() {
List myList;
for (int i = 1; i <= 10; ++i) {
myList.push_front(i);
}
myList.show_list();
return 0;
}
- 友元类不能传递
class A{
friend class B;
......
};
class B{
friend class C;
......
};
class C{
A;//不能进行访问
};
三.内部类
1.概念:如果一个类定义在另一个类的内部,就叫做内部类
class List {//外部类
public:
class iterator {//内部类
public:
void show()const {
cout << "List::iterator::show()." << endl;
List lt;
lt.m_a = 10;//内部类可以通过外部类的对象参数来访问外部类中的所有成员
}
private:
int m_c = 0;
};
private:
int m_a = 0;
int m_b = 0;
};
void main() {
//List::iterator it;
//it.show();
cout << sizeof(List) << endl;
}
注意:内部类就是外部类的友元类。注意友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
2.特性:
- 内部类可以定义在外部类的public,protected,private都可以
- 内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名
- sizeof(外部类) = 外部类,和内部类没有任何关系
上述代码求得sizeof(List) = 8,即 m_a 占4个字节,m_b 占4个字节,共8个字节,和内部类无关