C++学习笔记 this指针,对象数组,对象指针数组;
一,this指针
this指针不是对象的一部分,this指针所占的内存大小是不会反应在sizeof操作符上的,this指针的类型取决与使用this指针的成员函数类型以及对象类型
也是一个const指针,它的值是不能被修改的,它指向当前对象,通过它可以访问当前对象的所有成员;
this只能用在类的内部,但只有在对象被创建以后才会给this赋值,并且这个赋值的过程是编译器自动完成的,用户不能显式赋值。
通过this可以访问类的所有成员,包括private,protected,public属性的。this是一个指针,要用->来来访问成员变量或成员函数
this到底是什么?this实际上成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给this,不过this这个形参时隐式的,它并不出现在代码中,而是在编译阶段由编译器默认地将它添加到参数列表中。同时成员函数和成员变量关联的桥梁。
注意:友元函数没有this指针,因为友元不是类的成员,只有成员函数才有this指针;静态成员函数没有this指针。
二,对象数组
1 class M 2 { 3 public: 4 M(int i,int j) 5 { 6 m = i; n = j; cout << "Constructor Called!" << endl; 7 } 8 M() { m = n = 0; cout << "Default Constructor Called!" << endl; } 9 10 ~M() { cout << "Destructor Called!" << m << "," << n << endl; } 11 int Getm() { return m; } 12 int Getn() { return n; } 13 14 private: 15 int m, n; 16 }; 17 M mm1[2]; 22 int main() { 23 M mm2[4] = { M(2,3),M(5,6),M(7,8),M(2,5) }; 24 M a = M(10, 100); 25 mm1[0] = mm2[0]; 26 mm1[1] = M(50, 90); 27 cout <<"mm1[0]=(" << mm1[0].Getm() << "," << mm1[0].Getn() << ")" << endl; 28 cout << "mm1[1]=(" << mm1[1].Getm() << "," << mm1[1].Getn() << ")" << endl; 29 for(int i=0;i<4;i++) 30 cout << "mm2["<<i<<"] = (" << mm2[i].Getm() << ", " << mm2[i].Getn() << ")" << endl; 31 32 33 return 0; 34 }
数组其实也可以容纳复杂的数据类型,比如程序员定义的结构或对象。这一切所需的条件就是,每个元素拥有相同类型的结构或同一类的对象
1,数组的元素可以时对象
2,如果在创建对象数组时为使用初始化列表,则会为数组中的每个对象调用默认构造函数
3,没有必要让数组中的所有对象都使用相同的构造函数
4,如果在创建对象数组时使用初始化列表,则将根据所使用参数的数量和类型为每个对象调用正确的构造函数
5,如果沟站是需要多个参数,则初始化必须采用构造函数调用的形式
6,如果列表中的初始化项调用少与数组中的对象,则将为所有剩余的对象调用默认构造函数
三,对象指针
每一个对象在初始化后都会在内存中占有一定的空间。因此,即可以通过对象名访问一个对象,也可以通过对象地址来访问一个对象。
对象指针就是用于存放对象地址的变量。声明对象指针的一般语法形式为:类名* 对象指针名;
(1)用指针访问单个对象成员
- 定义指针变量:
Date *p,date1;
- 初始化:指向一个已创建的对象
p=&date1;
- 访问:用“->”操作符,只能访问该对象的公有成员。
(2)用对象指针访问对象数组
对象指针不仅能访问单个对象,也能访问对象数组.
指向类的成员的指针
类的成员自身也是一些变量、函数或者对象等。因此,也可以直接将它们的地址存放到一个指针变量中,这样就可以使指针直接指向对象的成员,进而可以通过指针访问对象的成员。
可在类外定义指向类的成员的指针来控制对象的成员。
注意:
- 指向成员的指针只能访问公有数据成员和成员函数。
- 使用要先声明,再赋值,然后访问。
(1)指向数据成员的指针
- 声明: 类型说明符 类名:: *数据成员指针名
- 赋值: 数据成员指针名=&类名:: 数据成员名
- 使用
- 对象名. *数据成员指针名
- 对象指针名->*数据成员指针名
指向可访问无歧义非虚基类的数据成员的指针,可以隐式转换成指向派生类的同一数据成员的指针:
1 struct Base { int m; }; 2 struct Derived : Base {}; 3 4 int main() 5 { 6 int Base::* bp = &Base::m; 7 int Derived::* dp = bp; 8 Derived d; 9 d.m = 1; 10 std::cout << d.*dp << ' ' << d.*bp << '\n'; // 打印 1 1 11 }
相反方向的转换,即从指向派生类的数据成员的指针到指向无歧义非虚基类的数据成员的指针,允许由 static_cast 和显式转型来进行,即使基类并无该成员(但当用该指针访问时,最终派生类中有)亦可:
1 struct Base {}; 2 struct Derived : Base { int m; }; 3 4 int main() 5 { 6 int Derived::* dp = &Derived::m; 7 int Base::* bp = static_cast<int Base::*>(dp); 8 9 Derived d; 10 d.m = 7; 11 std::cout << d.*bp << '\n'; // OK:打印 7 12 13 Base b; 14 std::cout << b.*bp << '\n'; // 未定义行为 15 }
成员指针的被指向类型也可以是成员指针自身:成员指针可为多级,而且在每级可以有不同的 cv 限定。亦允许指针和成员指针的混合多级组合:
1 struct A 2 { 3 int m; 4 // 指向非 const 成员的 const 指针 5 int A::* const p; 6 }; 7 8 int main() 9 { 10 // 指向数据成员的非 const 指针,该成员是指向非 const 成员的 const 指针 11 int A::* const A::* p1 = &A::p; 12 13 const A a = {1, &A::m}; 14 std::cout << a.*(a.*p1) << '\n'; // 打印 1 15 16 // 指向 const 的成员指针的常规非 const 指针 17 int A::* const* p2 = &a.p; 18 std::cout << a.**p2 << '\n'; // 打印 1 19 }
语法 | 含义 |
---|---|
const T* | 指向 const 对象的指针 |
T const* | 指向 const 对象的指针 |
T* const | 指向对象的 const 指针 |
const T* const | 指向 const 对象的 const 指针 |
T const* const | 指向 const 对象的 const 指针 |
(2)指向成员函数的指针
- 声明: 类型说明符 (类名∷ *指针名)(参数表);
- 赋值: 成员函数指针名 = 类名∷成员函数名;
- 使用
- (对象名.*成员函数指针名)(参数表);
- (对象指针名 -> *成员函数指针名) (参数表);
函数的指针是对象,从而能存储与数组,被复制,被赋值。
1 int f(int n){ 2 std::cout<<n<<std::endl; 3 return n*n; 4 } 5 6 int main(){ 7 int (*p)(int)=f; 8 int x=p(7); 9 10 }
解引用函数指针生成标识被指向函数左值;
1 int f(); 2 int (*p)() = f; // 指针 p 指向 f 3 int (&r)() = *p; // 将标识 f 的左值绑定到引用 4 r(); // 通过左值引用调用函数 f 5 (*p)(); // 通过函数左值调用函数 f 6 p(); // 直接通过指针调用函数 f