【Cpp】第二章-类和对象-下

类和对象

初始化列表

  我们之前想要在类创建时就对类进行初始化时使用构造函数直接在构造函数中对成员变量进行赋值。但是这种方法并非是最好的方法,并且有一些情况比如说常成员函数我们就无法在构造函数中初始化,因此有了新的对成员进行初始化的方法——初始化列表

使用

  初始化列表是和构造函数写在一起的,会在执行成员函数函数体之前优先利用初始化列表对成员变量赋予初值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
using std::cout;
using std::endl;
class A
{
public:
A(int x = 4, int y = 5):_x(x), _y(y)
{

}
int GetX()
{
return _x;
}
int GetY()
{
return _y;
}
private:
int _x;
int _y;
};
class Test
{
public:
Test(int a, int& b, int c, A d):_a(a), _b(b), _c(c), _d(d)
{
cout << _a << "\t" << _b << "\t" << _c << "\t" << _d.GetX() << "\t" << d.GetY() << endl;
cout << "building seccess" << endl;
}
private:
const int _a;
int& _b;
int _c;
A _d;

};
int main()
{
int b = 2;
A d;
Test(1, b, 3, d);
}

  在初始化列表中进行成员的初始化是最优的,因为对于自定义的类一定会先用初始化列表进行初始化。

特性

  1、有几种一定需要在初始化列表中才能进行初始化的成员变量:常成员,引用,没有默认构造函数的自定义类类型成员

  2、类类型成员不论是否在初始化列表中是否显示初始化都会自动在初始化列表中进行构造函数的调用。

  3、每个成员在初始化列表中只能出现一次。

  4、初始化顺序与初始化列表无关,只与成员在类中声明先后有关。

  5、优先在初始化列表中初始化所有成员,尤其是类类型成员。

explicit关键字

  我们在对对象进行初始化的时候可以进行这样的构造。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>               
using std::cout;
using std::endl;
class A
{
public:
A(int x, int y = 5):_x(x), _y(y)
{

}
int GetX()
{
return _x;
}
int GetY()
{
return _y;
}
private:
int _x;
int _y;
};
int main()
{
A a = 4;//等同A a(4);
cout << a.GetX() << "\t" << a.GetY() << endl;
}

  这种构造函数的调用仅适用于调用只有一个参数的构造函数,这种情况下可以达到隐式转换的效果。但是如果我们不想支持这种隐式转换呢?我们就可以在构造函数前加上explicit关键字,这样就可以仅用构造函数的隐式转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
explicit A(int x, int y = 5):_x(x), _y(y)
{

}



[misaki@localhost 第二章-类和对象]$ make
g++ -g Init.cpp -o Init
Init.cpp: 在函数‘int main()’中:
Init.cpp:40:9: 错误:请求从‘int’转换到非标量类型‘A’
A a = 4;
^
make: *** [Init] 错误 1

static静态成员

静态成员变量和静态成员函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
using namespace std;
class Test
{
public:
Test()
{
_num++;
}
static int GetNum()
{
return _num;
}
private:
static int _num;//静态成员变量
};
int Test::_num = 0;//在类外进行初始化
int main()
{
Test test[4];
cout << Test::GetNum() << endl;//用类+域限定符调用静态成员函数
}


[misaki@localhost 第二章-类和对象]$ ./static
4

  静态成员是属于整个类的成员,同时也是属于所有类的实例化对象的成员,它们在类被定义后即被初始化,静态成员可以被所有的实例化对象操作。

  以上这个代码我们用静态成计算类的构造函数调用次数。

特性

  1、静态成员变量必须在类外进行初始化。

  2、静态成员函数中不含this指针因此不可以使用非静态成员。

  3、静态成员属于这个类和所有实例对象因此用类或者对象都可以调用静态成员,前提其是公有。

  4、非静态成员函数也可以调用静态成员。

static作用

  这里我们又了解了static的新的作用,我们总结一下static一共有哪些作用。
  1、修饰局部变量,改变生命周期。

  2、修饰全局变量,改变链接属性,使其只在当前文件可见。

  3、修饰成员函数,将其变为静态,无this指针。

  4、修饰成员变量,将其变为静态成员变量。

为成员变量设置默认值(C++11)

  这个语法只有在支持11版本的编译器上才可以使用,这种语法相当于给成员变量设定了默认值,十分类似于参数缺省。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;
class Test
{
public:
Test(){}
int _a = 1;
int _b = 2;
};
int main()
{
Test t;
cout << t._a << "\t" << t._b << endl;
}


[misaki@localhost 第二章-类和对象]$ ./default
1 2

  这种设置默认值的语法如果我们并没有在构造函数中给成员变量赋值则会将其赋为这里的默认值。

友元

  有的时候我们想要在外部使用一个对象的成员变量但是又不想破坏其封装的时候就需要借助友元的语法,如果一个函数或者类是另一个类的友元,则这个函数或者类就可以自由使用另一个类中的私有成员。

友元函数

  例如我们要书写一个<<的重载函数让其可以按照我们的规则打印类中的成员,这个函数如果写在类中则左操作数永远被我们的类本身占据我们想要让ostream的对象作为左操作数的时候就只能定义在类外,看这样以来就无法访问类中的私有成员,这是我们就可以借助友元。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
using namespace std;
class Test
{
//将其声明为友元函数
friend ostream& operator<<(ostream& _cout, const Test& test);
private:
int _a;
int _b;
public:
Test(int a = 1, int b = 2):_a(a), _b(b)
{

}
};
ostream& operator<<(ostream& _cout, const Test& test)
{
_cout << test._a << "\t" << test._b << endl;
return _cout;
}
int main()
{
Test test;
cout << test;
}


[misaki@localhost 第二章-类和对象]$ ./friend
1 2

友元类

  友元类和友元函数一样,一旦一个类是另一个类的友元,他就可以访问其的私有成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>                                           
using namespace std;
class B;//前置声明
class A
{
//将其声明为友元类
friend class B;
//将其声明为友元函数
friend ostream& operator<<(ostream& _cout, const B& test);
private:
int _a;
int _b;
public:
A(int a = 1, int b = 2):_a(a), _b(b)
{

}
};
class B
{
friend ostream& operator<<(ostream& _cout, const B& test);
private:
int _a;
int _b;
A _classA;
public:
B(int a = 3, int b = 4):_a(a), _b(b)
{
//直接访问A类的私有成员
_classA._a = a;
_classA._b = b;
}
};
ostream& operator<<(ostream& _cout, const B& test)
{
_cout << test._a << "\t" << test._b << endl;
_cout << test._classA._a << "\t" << test._classA._b << endl;
return _cout;
}
int main()
{
B b;
cout << b;
}


[misaki@localhost 第二章-类和对象]$ ./friend
3 4
3 4

  以上这个例子综合使用了友元类和友元函数,友元类让B可以随意访问A的成员,但是要注意友元的关系是单向的,B是A的友元,但是A并不是B的友元,因此A不能访问B的成员。

内部类

  内部类是在一个类内部所定义的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>                                         
using namespace std;
class A
{
private:
int _a;
int _b;
static int num;
public:
A(int a = 1, int b = 2):_a(a), _b(b)
{
num++;
}
//内部类
class B
{
private:
int _a;
int _b;
public:
B(int a = 3, int b = 4):_a(a), _b(b)
{

}
void Test(A classA)
{
cout << classA._a << "\t" << classA._b << endl;
cout << _a << "\t" << _b << endl;
cout << num << endl;
}
};
};
int A::num = 0;
int main()
{
A::B b;//内部类的实例化
A a;
b.Test(a);
}

[misaki@localhost 第二章-类和对象]$ ./insideclass
1 2
3 4
1

特性

  1、内部类是外部类的友元类。

  2、外部类与内部类独立,不能用外部类访问内部类。

  3、对外部类取大小与内部类无关

  4、内部类可以不用加访问限定符就可以访问外部类的静态、枚举成员。# 类和对象

-------------本文结束感谢您的阅读!-------------
记录学习每一分,感谢您的赞助