静态成员的作用以及用法的总结,不论什么一个指针本身的类型都是unsigned
分类:多线程

静态成员函数可以直接访问该类的静态数据和函数成员。而访问非静态成员必须通过参数传递方式得到对象名,然后通过对象名来访问。

1.指针数组: 即 数组的元素是指针型;

类的静态成员分为静态数据成员和静态函数成员。先来看看类的静态数据成员:一、类的静态数据成员有什么用?

2.1 类的基础知识
2.2 构造函数
2.3 拷贝构造函数
2.4 析构函数
2.5 C++能自动产生成员函数
2.6 友元
2.7 类成员的补充
2.8 简单内存对象模型

#include<iostream>

例:int*pa[2];

  类实现了数据和数据的操作封装在一起,每个类的对象都会分配好内存来保存自己的数据成员,但是往往某个类的众多对象需要一些数据共享,比如定义了Person类,实例化了person1,person2,person3,但是我现在想知道我到底实例化了多少个person对象,怎么办?一个想法是定义一个count数据,这个数据为这些person对象共享,每个person都可以访问该count数据成员,这就是类的静态数据成员的作用:静态成员是解决同一个类的不同对象之间数据和函数共享的问题。

2.1 类的基础知识

using namespace std;
class point
{public:
  point(int xx=0,int yy=0){X=xx;Y=yy;} //构造函数
  point(point&p);                      //拷贝函数
  ~point(){countp--;}                  //析构函数
  int getX(){return X;}                //函数
  int getY(){return Y;}                //函数
  static void getC(){cout<<"object id="<<countp<<endl**;}  //静态成员函数
  private:
  int X,Y;                             //私有成员  
static int countp;                   //静态成员
};
point::point(point&p)                  //拷贝函数实现 
{X=p.X;
 Y=p.Y;
 countp++;
}
int point::countp=0;                  //静态数据成员的定义及初始化
int main()
{point A(4,5);                        //对象
 cout<<"point A,"<<A.getX()<<","<<A.getY();
 A.getC();                            
 point B(A);                          //要用到拷贝函数,用对象A初始化对象B
 cout<<"point B,"<<B.getX()<<","<<B.getY();  
point::getC();**                       //对静态成员函数直接调用,当然也可以用对象名调用  
 }

明明是一维的指针数组。竟当作二维数组用。

  二、怎么定义一个静态数据成员用关键字 static 来定义,比如 static int count .三、实例看如下代码:<span style="font-size: 14px;">class Point { public:Point(int m=0, int n=0 )

面向对象基本概念

类和对象
类是一组具有相同属性和行为的对象的抽象。类和对象的关系是抽象和具体的关系。
封装、继承和多态

  1. 用类进行封装
  2. 继承:保持已有类的特性而构造新类的过程。
  3. 多态:使编译器能够在运行时决定是使用基类中定义的函数还是派生类中定义的函数。

抽象和封装
在 C++ 中,用类来定义自己的抽象数据类型
通过定义类型来对应所要解决的问题中的各种概念,可以使我们更容易编写、调试和修改程序。
class Clock{
public:
void SetTime(int SetHour, int SetMinute);
void ShowTime();
private:
int m_Hour; int m_Minute
};
类是有着共同特征与行为、而状态各不相同的物体的总称。
对象是类的实现,是类的实例。类的产生基础是封装。

封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只需要通过外部接口,以特定的访问权限使用其中的成员即可。
C++支持数据隐藏机制,public,protected, private成为保护标识符,标识后边成员的可访问性。

[cpp] view plain copy

  { this->x = m ;this->y = n  ;this->count ++ ;} ~Point() { this->count —— ; } int getX() { return this->x ;} int getY() { return this->y ;} void ShowCount() { cout << "The numbers of count are :" << this->count << endl;} private:int x ;int y ;static int count ;} <br>int Point::count = 0 ;</span> count 就被定义为 静态成员变量,那么 count 就可以为所有的Point 对象所共享,通过对象名。ShowCount 来访问 count:Point A(4,5) ;A.ShowCount() ;  //  1 Point B(A) ;B.ShowCount()   // 2 count 为 静态成员,每个对象的创建和销毁都会影响到count .四、静态数据成员需要注意的地方1. 静态数据成员不属于任何一个对象,它只属于类。

成员函数

可以仅在类中说明原型,而在类外给出函数体实现,也可以直接在类中给出函数体,形成成员函数的隐含内联。
允许成员函数为重载函数和带默认参数值的函数。
对成员数据的使用不再遵循“先声明后使用”的原则。
凡被调用的成员函数一定要有函数实现。

:: ---- 作用域操作符,类就是定义了一个新的作用域。
void Clock::SetTime(int SetHour, int SetMinute)
{
m_Hour = SetHour;
m_Minute = SetMinute;
}
内联显示声明:
inline int Point::GetX() {
return X;
}

  1. //利用指针数组存放单位矩阵  
  2. #include <iostream>  
  3. using namespace std;  
  4. void main()  
  5. {  
  6.     int line1[]={1,0,0}; //声明数组,矩阵的第一行  
  7.     int line2[]={0,1,0}; //声明数组,矩阵的第二行  
  8.     int line3[]={0,0,1}; //声明数组。矩阵的第三行  
  9.     int* p_line[3];//声明整型指针数组  
  10.   
  11.     //对指针数组元素赋初值  
  12.     p_line[0]=line1;  
  13.     p_line[1]=line2;  
  14.     p_line[2]=line3;  
  15.   
  16.     //输出单位矩阵  
  17.     cout<<"Matrix test:"<<endl;  
  18.     for(int i=0;i<3;i++) //对矩阵每一行循环  
  19.     {  
  20.         for(int j=0;j<3;j++)//对数组元素循环  
  21.         {   
  22.             //明明是一维的指针数组。竟当作二维数组用  
  23.             cout<<p_line[i][j]<<" ";   
  24.         }  
  25.         cout<<endl;  
  26.     }  
  27. }  

  2. 静态数据成员的初始化要在实例化对象之前,否则你要是用 类名::静态数据成员 来访问 (这个可以在没有实例化对象)输出错误结果。

创建对象

对象就是类的实体,就是把抽象出的数据具体化。类就是一个封装了数据和函数的类型。
添加头文件#include "clock.h"
Clock myclock; //创建对象,就像是创建一个基本类型
myclock.SetTime(12, 30); //对象名.成员

一般来说类的定义与类中成员函数的定义并不放在同一个文件中。类的声明放在头文件中,类中函数的定义(类实现及类使用)放在.cpp文件中

输出结果:

  3. 一般静态成员不能在内联函数中访问。

类的深入

类:1、把数据封装(使用private),维护方便。2、使程序更加模块化,逻辑更清晰。
类用户的代码中永远不会出现private封装起来的内容。
Class默认为私有,struct默认为公有

类作用域
类定义部分 {}
类外成员函数形参表部分
类外成员函数函数体部分

成员函数的返回类型不一定在类作用域中
类内定义typedef int HOUR; 类外使用HOUR Clock::GetHour(){ }编译错误。

  1. 作用域是对象或成员能被使用的前提,表现了“可见性”。是语法规定好的,程序员只能遵照执行。
    2.访问权限是类的对象访问成员的被许可性,也是类成员的可用性。表现了“封装性”。是在作用域的前提下,由程序员定义的,是人的意志的体现

类内访问 和 类外访问
类作用域内的访问为“类内访问”,类作用域外的访问为“类外访问”
类内访问:
void Clock::SetTime(int newHour, int newMinute){
m_Hour = newHour;
m_Minute = newMinute;
}

Matrix test:
1 0 0
0 1 0
0 0 1

  五、 类的静态函数成员在上面的例子中,每个对象都与一个 ShowCount 的拷贝,可以与 类的静态数据成员一样,设为共享方式。这就需要定义为静态函数成员了。

拷贝构造函数:

Clock(const Clock& c1): m_Hour(c1.m_Hour),m_Minute(c1.m_Minute) {
cout<<"拷贝构造函数调用"<<endl;
}
X(p.X)是当前对象的函数访问别的对象的私有数据,这不是破坏了封装性吗?
不。这是发生在成员函数中,叫“类内访问”:成员函数和私有数据都在同一个类中。而不属于“对象名.成员名”的表示,那是“类外访问”。

2.指针型函数
当函数的返回值是地址时,该函数就叫指针形函数,又叫返回指针的函数。

  相关定义如下:class Point { public:Point( int m , int n ) { x = m ; y = n ; count++ ;} Point( Point & p) ;~Point() { count—— ;} static void ShowCount() { cout << count << endl; } private:int x ;int y ;static int count ;} int Point::count = 0 ; // 注意初始化的方式在如下代码中:Point A(4,5) ;A.ShowCount() ; // 通过对象名引用Point:: ShowCount() // 通过类名来引用,推荐使用这个方式需要注意的是,静态成员函数中不可以使用 this 指针,一般是用来访问 静态数据成员的,不做其他用途。(访问非静态成员需要通过参数传递对象名,通过对象名来访问)。

隐含的this指针

void Clock::SetTime( int SetHour, int SetMinute)
{
this->m_Hour = SetHour;
this->m_Minute = SetMinute;
}
this指针是什么,在面向对象编程中,针对结构体,会有相关的成员函数,而成员函数的第一个参数通常就是本类对象的指针,既然这是一个固定的方法,C++索性就把它给封装在后边。本类对象的所有代码是公共的。
每一个成员函数(static member function除外)都有一个隐含的参数,为 classType* this,会自动加载进去。
SetTime( Clock* this, int SetHour, int SetMinute)


2.2 构造函数

声明形式:数据类型* 函数名( )

类实现了数据和数据的操...

定义及作用

构造函数是特殊的成员函数,通常创建类类型的新对象,都要执行构造函数。
构造函数的工作是保证每个对象的数据成员具有合适的初始值
构造函数的作用是在对象被创建时使用特定的值构造对象,或者说将对象初始化为一个特定的状态。
特殊在哪儿?1.不能由对象调用,自动调用!2.没有返回值。3.有初始化列表

初始化:是指对象(变量)诞生的那一刻即得到原始值的过程。是动词。
若对象声明然后再赋值,会经历状态由不确定到确定的过程。
调用时机
当然是在任何构造对象的时候:
a) 无论这个对象有名无名.
b) 无论这个对象被创建在什么区域.
c) 无论这个对象是否为临时对象.
Clock clock;
Clock *pClock = new Clock;

如果程序中未声明,则系统自动产生出一个默认形式的构造函数,它无参,函数体为空;
允许为内联函数、重载函数、带默认形参值的函数
是可以使用初始化列表的两函数之一(特权(另一个拷贝构造函数));
不可以是常函数,亦不可是虚函数;
天然具有类型转换功能,除非用explicit关闭。

指针型函数的使用(串连接)

语法规则及特殊性体现

类名::类名(形参总表):成员或对象1(参数1),成员或对象2(参数2)
{
构造函数的函数体
}

Clock::Clock(int h, int m):m_Hour(h), m_Minute(m)
{
}
构造函数名与类名相同 //一个类可以有多个构造函数
不可有任何返回值
可以有初始化列表(只有构造函数有初始化列表)

[cpp] view plain copy

初始化列表

Clock::Clock(int h, int m) 这里是初始化的时机
{
//如果放弃了初始化的时机,那么就要在这里进行数据成员的赋值
m_Hour = h;
m_Minute = m;
//m_serial_number = “CASIO-EDIFICE-2009001”;
}

注意,无论是否写初始化列表,在进入函数体之前,都有一个初始化的机会。
这个机会留给你初始化特殊的成员变量,如引用,const成员
例如: const string m_serial_number;

倔强变量需要初始化列表
const变量
引用
IO流对象 //你可以暂且先记住它
所以,如果类内包含这三类成员,一定要使用初始化列表对他们进行初始化工作。
建议使用初始化列表给成员初始化,因为效率比赋值高

默认构造函数
A a; //类名 对象名; 不带任何初值
那么编译器为你调用的构造函数就是默认构造函数。

构造对象的方式
有名对象:A a 或A a(参数)
无名对象(堆): new A 或 new A(参数)
注:A a;千万不可写成 A a();

规范:初始化列表一定要按照成员变量的声明次序书写,以免引发隐晦的错误。
A() { j = 10; i = j/2;} // A():j(10), i(j/2) {}


2.3 拷贝构造函数

使用一个已经存在的对象去初始化同类的一个新对象时调用拷贝构造函数
拷贝构造函数是一种特殊的构造函数,其形参为本类的对象引用。
规范,建议使用const引用

语法规则
class 类名
{
public:
类名(形参);//构造函数
类名(const 类名 &参数名);//拷贝构造函数原型
};
类名::类名(const 类名 &参数名) //拷贝函数的实现
{
函数体
}
Clock(const Clock& c1): m_Hour(c1.m_Hour),m_Minute(c1.m_Minute) {
cout<<"拷贝构造函数调用"<<endl;
}
调用方式
当用类的一个对象去初始化该类的另一个对象时系统自动调用拷贝构造函数实现拷贝赋值。
void main(void)
{
Clock c1(1,2);
Clock c2(c1); //拷贝构造函数被调用
}
若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数
void fun1(Clock c)
{
cout<<c.GetHour()<<endl;
}
int main()
{
Clock c1(1,2);
fun1(c1);
return 0;
}
当函数的返回值是类对象时,系统自动调用拷贝构造函数。
Clock fun2(){
Clock c(1,2);
//调用拷贝构造函数
return c;
}
void main()
{
Clock c1;
c1 = fun2(); //临时对象
}


2.4 析构函数

定义:(与构造函数相对立)
用来完成对象被删除前的一些清理工作。
析构函数是在对象的生存期即将结束的时刻被自动调用的
语法规则:
类名::~类名()
{
函数体
}
注:
函数名为 ~类名
函数没有参数
函数体负责资源清理工作(内存)

为什么需要析构函数?
处理僵死进程。
Array(int size):m_Size(size) { m_pArray = new int[m_Size]; }
~Array(){
delete [] m_pArray;
}
析构函数的调用顺序与构造函数的调用顺序严格相反
发生了2次析构函数的调用,用new分配空间,需要在delete的时候才会调用析构函数
int main()
{
Test a;
{
Test *pTest = new Test;
Test b;
delete pTest;
pTest = NULL;
}
return 0;
}

  1. //指针型函数的使用(串连接)  
  2. #include <stdio.h>  
  3. char *my_cat(char *p1, char *p2)  
  4. {  
  5.     static char a[160],*p;  
  6.     p=a;  
  7.     while (*p1 != '') *p++=*p1++;  
  8.     while (*p2 != '') *p++=*p2++;  
  9.     *p=*p2;  
  10.     return a;  
  11. }  
  12.   
  13. void main()  
  14. {  
  15.     char s1[80],s2[80];  
  16.     printf("n请输入第一串字符: ");  
  17.     //注意:scanf和cin在输入字符串时,遇到空格就终止,而gets 不会。  
  18.     gets(s1);  
  19.     //cin >> s1;  
  20.     //scanf("%s", s1);  
  21.     fflush(stdin);  
  22.     printf("n请输入第二串字符: ");  
  23.     gets(s2);  
  24.     //cin >> s2;  
  25.     //scanf("%s", s2);  
  26.     printf("n连接结果: n");  
  27.     printf("n第一串在前第二串在后: %s n",my_cat(s1,s2));  
  28.     printf("n第二串在前第一串在后: %s n",my_cat(s2,s1));  
  29. }  

MyString类函数练习

错误调试:注意赋值与等于符号、注意动态申请的内存delete

#include <iostream>
#include <cstring>

using namespace std;

class MyString {
public:
    MyString(char *pstr="");
    MyString(const MyString& str);
    ~MyString();
public:
    void ShowString();  //显示字符串
    void Add(const MyString& str);  //与另外一个相加
    void Copy(const MyString& str); //从另外一个拷贝
    int GetLength() const;
private:
    char *m_buf;
};
MyString::MyString( char *pstr)
{
    if(pstr)
    {
        m_buf = new char[strlen(pstr) +1];
        strcpy(m_buf, pstr);
    }
    else
    {
        m_buf = new char[1];
        *m_buf = '';
    }
}
MyString::MyString( const MyString& str)
{
    m_buf = new char[ strlen(str.m_buf) +1 ];
    strcpy( m_buf, str.m_buf);
}

MyString::~MyString( )
{
    delete[] m_buf;
}
void MyString::ShowString( )
{
    if(*m_buf!= '')
    {
        cout<< m_buf <<endl;
    }
    else
    {
        cout << "This is a NULL string" << endl;
    }
}

void MyString::Add(const MyString& str)
{
    if( *str.m_buf == '' )
        return;
    int nLength = GetLength();
    char *pTmp = new char[nLength];
    strcpy(pTmp, m_buf );
    delete [] m_buf;
    m_buf = new char[ (nLength-1) + str.GetLength()  ];
    strcpy(m_buf, pTmp);
    strcat( m_buf, str.m_buf);
    delete[] pTmp;
}
void MyString::Copy(const MyString& str)
{
    delete [] m_buf;
    m_buf = new char[ strlen(str.m_buf) +1 ];
    strcpy( m_buf, str.m_buf);
}
int MyString::GetLength() const
{
    int i = (int)strlen(m_buf)+1;
    return i;
}

int main()
{

    MyString str("hi ");
    MyString str2("You are welcome!");
    str.ShowString();
    str2.ShowString();
    str.Add(str2);
    str.ShowString();
    return 0;
}

2.5 C++能自动产生成员函数

C++能自动产生的成员函数(空类)
构造函数 类名{}
拷贝构造函数 类名(类名& ){}
赋值函数 类名& operator =(类名& );
析构函数 ~类名(){}
空类在不同的编译器下占几个字节。
class Empty{};
const Empty e1; // 缺省构造函数
Empty e2(e1); // 拷贝构造函数
e2 = e1; // 赋值运算符重载函数
最后调用析构函数。
生成的析构函数一般是非虚的。除非是从虚析构函数的基类继承而来


2.6 友元

友元机制:允许一个类将对其非公有成员的访问权授予指定的函数或类。
友元的声明以关键字 friend开始。它只能出现在类定义的内部
注意:

  1. 友元声明可以出现在类中的任何地方,但通常将友元声明成组地放在类定义的开始或结尾。
  2. 友元不是授予友元关系的那个类的成员,所以它们不受声明出现部分的访问控制影响。

友元分类
方法一:声明整个类为友元
friend class RepairMan;

方法二:声明类中的某个成员函数为友元
friend bool RepairMan::RepairClock(Clock& clock);

方法三:声明一个非成员函数为友元。(其他类的非成员函数,自身)
friend bool RepairClock(Clock& clock);

特性
友元函数不是类的成员,因此不受类的作用域管辖。
可以访问对象的私有成员,但必须由对象名来引导。(对象为媒介,通过友元机制)

性质
友元关系是单向的。
B类是A类的友元,则B类的函数可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据。(孙悟空钻进铁扇公主肚里。)
友元关系不能传递 朋友的朋友不见得是朋友!
友元关系不能继承
如果B类是A类的友元, B类的子类不会自动成为A类的友元类。(借来的东西不是遗产。)


2.7 类成员的补充

const 数据成员
const 成员函数
static 数据成员
static 成员函数

执行结果:

const数据成员 (对象诞生之后其const数据成员不能改变)

const string m_serial_number;
const成员函数
const修饰this指针
this不再是:Type* const this;而是:const Type* const this;
const需要在声明和定义中写出
const成员函数内部无法修改数据成员
const函数内部无法调用non-const成员函数
const 对象 不可以访问 非const 成员函数

例子解析:
1、如果没有const成员函数,使用const对象调用成员函数会出错
不能将“this”指针从“const Clock”转换为“Clock &”转换丢失限定符
2、常对象只能调用常成员函数;在常函数和非常函数并存时,非常对象只能调用非常函数,在只有常函数时,非常对象可以调用常函数。

请输入第一串字符: dalian
请输入第二串字符: i love you
连接结果:
第一串在前第二串在后: daliani love you
第二串在前第一串在后: i love youdalian

static数据成员

non-static 数据成员是对象属性的成员。
static 数据成员是类属性的成员。

内存:堆、栈、data、code
数据成员变量: int a 堆
主函数main()、静态函数、成员函数code
静态数据成员 data
Int main(int argc,char **avgr){} 参数放在栈中
Class A{};
A *p; *p 栈

类属性
静态数据成员
用关键字static声明;
该类的所有对象维护着同一份拷贝;
不能在构造函数中而应在类外单独进行初始化。必须在程序运行之前完成,并且用(::) 来指明所从属的类名。
声明: //.h class 内
static 类型 成员名;
定义: //.cpp 内(无static)
类型 类名::静态成员名 = 初值; or
类型 类名::静态成员名(参数表);

静态成员函数
类外的代码可以使用类名和作用域操作符(::)来调用静态成员函数;
静态成员函数只能访问属于该类的静态数据成员或静态成员函数,不能使用非静态成员。
没有this指针,所以不能为常函数。
函数声明有static修饰,如果类外实现,不加static修饰

使用:
a) 对象名.XXX //指针->XXX
b) 类名::XXX //建议采用这种方式


2.8 简单内存对象模型

组合
class A{}; class B{A a;};
初始化:
类名::类名(形参总表) :对象1(参数),对象2(参数)
{
构造函数的其他功能
}
给类作对象布局的安排:让类的对象中含有一个别的类对象,在本对象的适当位置处,调用那个类的构造函数,来产生内嵌对象作为本类的数据成员。
聚合(指针或引用,关系性紧密)
Class A{}; class B{A *a;};
例子:
class Point
{
private:
float x, y; //点的坐标
public:
Point(float h, float v); //构造函数

float GetX(void){return x;} //取X坐标取坐标
float GetY(void){return y;} //Yvoid Draw(void); //在(x,y)处画点

};

Point::Point(float h, float v){//构造函数
x = h;
y = v;
}

class Line
{
private:
Point p1,p2; //线段的两个端点
public:
Line(Point a,Point b):p1(a), p2(b)
{ //构造函数

}
void Draw(void); //画出线段

};
void main()
{
Point point1(1,1);
Point point2(1,2);
Line line1(point1, point2);
}

3.指向函数的指针

3.1指向函数的指针

声明形式:  数据类型 (*函数指针名) ( 形參表);

含义: 数据指针指向的是数据存储区;而函数指针指向的是程序代码存储区。函数名就是地址。

图片 1

3.2  指向函数的指针数组:   指向函数的指针可组成数组。

        声明形式;   数据类型 (*函数指针名[ ] )( 形參表);

图片 2

[cpp] view plain copy

  1. /************************************************************************ 
  2. 练习:写一个程序,依据用户的输入数据算出结果: 
  3. 仅仅写出四种运算就能够。 
  4. 比如: 
  5. 1 + 2 = 3 
  6. 1 * 2 = 2 
  7. 1 –2 = -1 
  8. 1 / 2 = 0 
  9. **************************************************************************/  
  10. #include <stdio.h>  
  11. #include <stdlib.h>  
  12.   
  13. typedef int (*pFun[])(int,int);  
  14. int add(int,int);  
  15. int sub(int,int);  
  16. int mul(int ,int);  
  17. int divide(int,int);  
  18. void main()  
  19. {  
  20.     pFun pfun = {mul,add,NULL,sub,NULL,divide};  
  21.     //也能够这样:int (*pfun[])(int,int) ={mul,add,NULL,sub,NULL,divide};  
  22.     int item1,item2;  
  23.     int result;  
  24.     char op;  
  25.     do   
  26.     {  
  27.         printf("Please input :n");  
  28.         fflush(stdin);  
  29.         scanf("%d %c %d",&item1,&op,&item2);  
  30.         result = pfun[op-'*'](item1,item2);    //用到了是 + - * /  的ASCII特性  
  31.         printf("%d %c %d = %d n",item1,op,item2,result);  
  32.         printf("try again ? please input y\nn");  
  33.         fflush(stdin);  
  34.         scanf("%c",&op);  
  35.     } while(op == 'y');  
  36. }  
  37.   
  38. int add(int a,int b)  
  39. {  
  40.     return (a+b);  
  41. }  
  42. int sub(int a,int b)  
  43. {  
  44.     return (a-b);  
  45. }  
  46. int mul(int a,int b)  
  47. {  
  48.     return a*b;  
  49. }  
  50. int divide(int a,int b)  
  51. {  
  52.     if (b == 0)  
  53.     {  
  54.     exit(-1);  
  55.     }  
  56.     else  
  57.     return a/b;  
  58. }  

执行结果:

图片 3

这个样例用到了+ - * / 的ASCII码

图片 4

4.this指针

隐含于类中的每个非静态成员函数中的特殊指针。

明白地指出了成员函数当前所操作的数据所属的对象。

当通过一个对象调用成员函数时。系统先将该对象的地址赋给this指针。然后调用成员函数。成员函数对对象的数据成员进行操作时。

就隐含使用了this指针。(this是函数的第一个形參。)

5. 关于指向类成员的指针

5.1 指向类的非静态成员的指针

通过指向成员的指针仅仅能訪问公有成员

声明指向成员的指针
–声明指向公有数据成员的指针
类型说明符 类名::*指针名。
–声明指向公有函数成员的指针
类型说明符 (类名::*指针名)(參数表)。

注意:应当知道,指向成员的指针名曰指针。实则非也。它是个偏移量,记录着该成员距离对象的首址的距离。

            故定义它时,总要前缀着类名(类名::),以便于编译器识别后予以特别处理。

图片 5

使用指向数据成员的指针

对指向数据成员的指针赋值:  –说明指针应该指向哪个成员     指针名=&类名::数据成员名;

使用指向数据成员的指针:     –通过对象名(或对象指针)与成员指针联手来訪问数据成员                 

                                                       对象名.* 类成员指针名    或:  对象指针名->*类成员指针名

使用指向函数成员的指针

指向函数成员的指针               

–初始化指针名=类名::函数成员名;

–通过对象名(或对象指针)与成员指针结合来訪问函数成员

(对象名.* 类成员指针名)(參数表)    或: (对象指针名—>*类成员指针名)(參数表)

[cpp] view plain copy

  1. #include <iostream>  
  2. using namespace std;  
  3. class Point  
  4. {   
  5. public:  
  6.     Point();  
  7.     Point(int xx,int yy);  
  8.     Point(const Point &ref);  
  9.     ~Point();  
  10.     void Move(int x,int y);  
  11.     int GetX() {return X;}  
  12.     int GetY() {return Y;}  
  13.     void Print() const  
  14.     {cout << "X=" << X <<", "<< "Y=" << Y << endl;}  
  15. private:  
  16.     int X,Y;  
  17. };  
  18.   
  19. Point::Point()  
  20. {   
  21.     X=Y=0;  
  22. }  
  23. Point::Point(int xx,int yy)  
  24. {   
  25.     X = xx;  
  26.     Y = yy;  
  27. }  
  28. Point::Point(const Point &ref)  
  29. {  
  30.     X = ref.X;  
  31.     Y = ref.Y;  
  32. }  
  33. Point ::~Point()  
  34. {   
  35. }  
  36. void Point ::Move(int x,int y)  
  37. {   
  38.     X+=x; Y+=y;   
  39. }  
  40.   
  41. void main()  
  42. {  
  43.     Point A(4,5);  
  44.     //声明对象指针并初始化  
  45.     Point *p1=&A;  
  46.   
  47.     //声明成员函数指针并初始化  
  48.     int(Point::*p_GetX)()=Point::GetX;  
  49.     //(1)使用成员函数指针訪问成员函数  
  50.     cout<<(A.*p_GetX)()<<endl;  
  51.     //(2)使用对象指针訪问成员函数  
  52.     cout<<(p1->GetX)()<<endl;  
  53.     //(3)使用对象名訪问成员函数  
  54.     cout<<A.GetX()<<endl;  
  55. }  

5.2 指向类的静态成员的指针

对类的静态成员(类共享)的訪问不依赖于对象,能够用普通的指针来指向和訪问静态成员

通过指针訪问类的静态数据成员

[cpp] view plain copy

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. class Point//Point类声明  
  5. {  
  6. public://外部接口  
  7.     Point(int xx=0, int yy=0) {X=xx;Y=yy;countP++;} //构造函数  
  8.     Point(Point &p);//拷贝构造函数  
  9.     int GetX() {return X;}  
  10.     int GetY() {return Y;}  
  11.     static int countP;//静态数据成员引用性说明  
  12. private://私有数据成员  
  13.     int X,Y;  
  14. };  
  15.   
  16. Point::Point(Point &p)  
  17. {  
  18.     X=p.X; Y=p.Y; countP++;   
  19. }  
  20. int Point::countP=0;//静态数据成员定义性说明  
  21.   
  22. void main()  
  23. {   
  24.     //声明一个int型指针,指向类的静态成员  
  25.     int*count = &Point::countP;  
  26.     Point A(4,5);  
  27.     cout<<"Point A,"<<A.GetX()<<","<<A.GetY();  
  28.     //直接通过指针訪问静态数据成员  
  29.     cout<<" Object id="<<*count<<endl;  
  30.     Point B(A);//声明对象B  
  31.     cout<<"Point B,"<<B.GetX() <<","<<B.GetY();  
  32.     //直接通过指针訪问静态数据成员  
  33.     cout<<" Object id="<<*count<<endl;  
  34. }  

执行结果:

图片 6

通过指针訪问类的静态函数成员

[cpp] view plain copy

  1. #include <iostream>  
  2. using namespace std;  
  3. class Point//Point类声明  
  4. {   
  5. public://外部接口  
  6.     Point(int xx=0, int yy=0) {X=xx;Y=yy;countP++;} //构造函数  
  7.     Point(Point &p);//拷贝构造函数  
  8.     int GetX() {return X;}  
  9.     int GetY() {return Y;}  
  10.     static void GetC() //静态函数成员  
  11.     {cout<<" Object id="<<countP<<endl;}  
  12. private://私有数据成员  
  13.     int X,Y;  
  14.     static int countP;//静态数据成员引用性说明  
  15. };  
  16.   
  17.   
  18. Point::Point(Point &p)  
  19. {X=p.X; Y=p.Y; countP++; }  
  20. int Point::countP=0;//静态数据成员定义性说明  
  21.   
  22. void main()//主函数  
  23. {  
  24.     //指向类的静态成员函数的指针,  
  25.     void (*gc)()=Point::GetC;  
  26.     Point A(4,5);//定义对象A  
  27.     cout<<"Point A,"<<A.GetX()<<","<<A.GetY();  
  28.     gc();//通过指针訪问静态函数成员,输出对象序号  
  29.     Point B(A);//定义对象B  
  30.     cout<<"Point B,"<<B.GetX()<<","<<B.GetY();  
  31.     gc();//通过指针訪问静态函数成员  
  32. }  

执行结果:

图片 7

6.指针与数组的差别

数组名是静态的,一旦定义,其值就固定不变了。

而指针是动态的。可随时变化。

数组名是常量,不可作为算术运算的左值。指针是变量,可作为算术运算的左值。

在訪问速度上。用数组表达式慢,用指针快。

指针比数组有更大的灵活性。

如:

char a[10] [20]; //这是个固定了行和列的矩阵

char * b[10]; //有10行,但每行可长短不等

数组有更好的可读性,可随机訪问各元素;指针可读性差,更适合顺序訪问。

本文由10bet手机官网发布于多线程,转载请注明出处:静态成员的作用以及用法的总结,不论什么一个指针本身的类型都是unsigned

上一篇:没有了 下一篇:没有了
猜你喜欢
热门排行
精彩图文