精华内容
下载资源
问答
  • 哪些函数不能成为虚函数... 静态成员函数:静态成员函数属于类的,不依赖于对象调用,所以也不能成为虚函数。 友元函数:友元函数不属于类的成员函数,不能被继承。对于没有继承特性的函数没有虚函数的说法。 内联

    哪些函数不能成为虚函数?

    1. 普通函数:普通函数不属于成员函数,是不能被继承的。普通函数只能被重载,不能被重写,因此声明为虚函数没有意义。因为编译器会在编译时绑定函数。
    2. 构造函数:当调用了构造函数才能产生对象,通过对象才能调用虚函数,这显然矛盾。
    3. 静态成员函数:静态成员函数是属于类的,不依赖于对象调用,所以也不能成为虚函数。
    4. 友元函数:友元函数不属于类的成员函数,不能被继承。对于没有继承特性的函数没有虚函数的说法。
    5. 内联函数:内联函数在编译时就被展开,它不能产生函数符号,所以不能往虚表中存放,自然就不能成为虚函数。

    构造函数不能为虚函数的再解释

    1.虚函数调用是在部分信息下完成工作的机制,允许我们只知道接口而不知道对象的确切类型。 要创建一个对象,你需要知道对象的完整信息。 特别是,你需要知道你想要创建的确切类型。 因此,构造函数不应该被定义为虚函数。

    2.虚函数对应一张虚函数表,这个虚函数表是存储在对象的内存空间的,如果构造函数是虚函数就需要通过虚函数表来调用,可是对象还没有实例化,也就是内存空间还没有,找不到虚函数表,所以构造函数是不能声明为虚函数的。

    析构函数作为虚函数---虚析构

    当子类有在堆上申请空间的操作,那么父类指针在释放时无法调用到子类的析构函数,这时就会造成内存泄漏。

    解决方式:将父类中的析构函数改为虚析构或者纯虚析构。

    虚析构和纯虚析构都可以解决父类指针释放子类对象,都需要有具体的函数实现。

    语法:

    • 虚析构:virtual ~类名(){}
    • 纯虚析构:virtual ~类名() = 0;
                        类名::~类名(){}

    下面一个例子:

    #include<iostream>
    using namespace std;
     
    class Animal {
    public:
    	Animal(){
    		cout << "Animal 构造函数调用!" << endl;
    	}
    	virtual void Speak() = 0;
     
    	/*//析构函数加上virtual关键字,变成虚析构函数
    	virtual ~Animal(){
    		cout << "Animal虚析构函数调用!" << endl;
    	}*/
     
    	virtual ~Animal() = 0; //纯虚析构函数 
    };
     
    Animal::~Animal(){
    	cout << "Animal 纯虚析构函数调用!" << endl;
    }
     
    //和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。
     
    class Cat : public Animal {
    public:
    	Cat(string name){
    		cout << "Cat构造函数调用!" << endl;
    		m_Name = new string(name);
    	}
    	virtual void Speak(){
    		cout << *m_Name <<  "小猫在说话!" << endl;
    	}
    	~Cat(){
    		cout << "Cat析构函数调用!" << endl;
    		if (this->m_Name != NULL) {
    			delete m_Name;
    			m_Name = NULL;
    		}
    	}
    public:
    	string *m_Name;
    };
     
    int main() {
    	Animal *animal = new Cat("Tom");
    	animal->Speak();
    	delete animal;
    	return 0;
    }

    总结:

    • ​ 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
    • ​ 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
    • ​ 拥有纯虚析构函数的类也属于抽象类

     

    展开全文
  • 静态函数可以分为全局静态函数和类的静态成员函数。 <br />Static关键字 在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所有对象来说,static...

    静态函数
    用static声明的函数是静态函数。静态函数可以分为全局静态函数类的静态成员函数

    Static关键字
    在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化对于该类的所有对象来说,static成员变量只有一份
    用static声明的方法是静态方法,在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。
    静态方法不再是针对于某个对象调用,所以不能访问非静态成员。
    可以通过对象引用或类名(不需要实例化)访问静态成员

    C++类静态数据成员与类静态成员函数
    函数调用的结果不会访问或者修改任何对象(非static)数据成员,这样的成员声明为静态成员函数比较好。且如果static int func(....)不是出现在类中,则它不是一个静态成员函数,只是一个普通的全局函数,只不过由于static的限制,它只能在文件所在的编译单位内使用,不能在其它编译单位内使用。
    静态成员函数的声明除了在类体的函数声明前加上关键字static,以及不能声明为const或者volatile之外,与非静态成员函数相同。出现在类体之外的函数定义不能制定关键字static。
    静态成员函数没有this指针

    在没有讲述本章内容之前如果我们想要在一个范围内共享某一个数据,那么我们会设立全局对象,但面向对象的程序是由对象构成的,我们如何才能在类范围内共享数据呢?

    这个问题便是本章的重点:声明为static的类成员或者成员函数便能在类的范围内共同享我们把这样的成员称做静态成员和静态成员函数。

    下面我们用几个实例来说明这个问题,类的成员需要保护,通常情况下为了不违背类的封装特性,我们是把类成员设置为protected(保护状态)的,但是我们为了简化代码,使要说明的问题更为直观,更容易理解,我们在此处都设置为public。

    以下程序我们来做一个模拟访问的例子,在程序中,每建立一个对象我们设置的类静态成员变自动加一,代码如下:

    #include <iostream>
    using namespace std;

    class Internet
    {
    public:
         Internet(char *name,char *address)
         {
             strcpy(Internet::name,name);
             strcpy(Internet::address,address);
             count++;
         }
     

         static void Internet::Sc()//静态成员函数
         {
             cout<<count<<endl;
         }

         Internet &Rq();
     

    public:
         char name[20];
         char address[20];
         static int count;//这里如果写成static int count=0;就是错误的
    };

    Internet& Internet::Rq()//返回引用的成员函数
    {
         return *this;
    }

    int Internet::count = 0;//静态成员的初始化

    void vist()
    {
         Internet a1("中国软件开发实验室","www.cndev-lab.com");
         Internet a2("中国软件开发实验室","www.cndev-lab.com");
    }
     

    void fn(Internet &s)
    {
         cout<<s.Rq().count;
    }


    void main()
    {
         cout<<Internet::count<<endl;//静态成员值的输出
         vist();
         Internet::Sc();//静态成员函数的调用
         Internet b("中国软件开发实验室","www.cndev-lab.com");
         Internet::Sc();
         fn(b);
         cin.get();
    }

    上面代码我们用了几种常用的方式建立对象,当建立新对象并调用其构造函数的时候,静态成员cout便运行加1操作,静态成员的初始化应该在主函数调用之前,并且不能在类的声明中出现,通过运行过程的观察我们发现,静态成员count的状态并不会随着一个新的对象的新建而重新定义,尽而我们了解到类的静态成员是属于类的而不是属于哪一个对象的,所以静态成员的使用应该是类名称加域区分符加成员名称的,在上面的代码中就是Internet::count,虽然我们仍然可以使用对象名加点操作符号加成员名称的方式使用,但是不推荐的,静态类成员的特性就是属于类而不专属于某一个对象。

    静态成员函数的特性类似于静态成员的使用,同样与对象无关,调用方法为类名称加域区分符加成员函数名称,在上面的代码中就是Internet::Sc();静态成员函数由于与对象无关系,所以在其中是不能对类的普通成员进行直接操作的。

    如果上面的 static void Internet::Sc()修改成为:
    static void Internet::Sc()//静态成员函数
    {
         cout<<name<<endl;//错误
         cout<<count<<endl;
    }


    静态成员函数与普通成员函数的差别就在于缺少this指针,没有这个this指针自然也就无从知道name是哪一个对象的成员了。

    根据类静态成员的特性我们可以简单归纳出几点,静态成员的使用范围:
    1.用来保存对象的个数。
    2.作为一个标记,标记一些动作是否发生,比如:文件的打开状态,打印机的使用状态,等等。
    3.存储链表的第一个或者最后一个成员的内存地址。

    为了做一些必要的练习,深入的掌握静态对象的存在的意义,我们以前面的结构体的教程为基础,用类的方式描述一个线性链表,用于存储若干学生的姓名,代码如下:

    #include <iostream>
    using namespace std;

    class Student
    {
    public:
         Student (char *name);
         ~Student();

    public:
         char name[30];
         Student *next;
         static Student *point;
    };

    Student::Student(char *name)
    {
         strcpy(Student::name,name);
         this->next=point;
         point=this;
    }

    Student::~Student ()//析构过程就是节点的脱离过程
    {
         cout<<"析构:"<<name<<endl;

         if(point==this)
         {
             point=this->next;
             cin.get();
             return;
         }

         for(Student *ps=point;ps;ps=ps->next)
         {
             if(ps->next==this)
             {
             cout<<ps->next<<""<<this->next<<endl;
             ps->next=next;//=next也可以写成this->next;
             cin.get();
             return;
             }
         }

         cin.get();
    }

    Student* Student::point=NULL;
    void main()
    {
         Student *c = new Student("marry");
         Student a("colin");
         Student b("jamesji");
         delete c;
         Student *fp=Student::point;
         while(fp!=NULL)
         {
             cout<<fp->name<<endl;
             fp=fp->next;
         }

         cin.get();
    }
     

    从上面的代码来看,原来单纯结构化编程需要的一个链表进入全局指针在这里被类的静态成员指针所替代(类的静态成员完全可以替代全局变量),这个例子的理解重点主要是要注意观察类成员的析构顺序,通过对析构顺序的理解,使用析构函数来进行节点的脱链操作。

    为什么虚函数必须是非静态成员函数
    如果定义为虚函数,那么它就是动态绑定的,也就是在派生类中可以被覆盖的,这与静态成员函数的定义本身就是相矛盾的。

    ==
    主要有两个作用: 
         1、管理静态数据成员; 
         2、提供类范围的功能,即不需要对象来实现的功能。 
    比如Symbian中的NewL/LC方法就是static的

    ==
    使用static关键字声明的函数成员是静态的,静态成员函数同样也属于整个类,由同一个类的所有对象共同维护,为这些对象所共享。

    作为成员函数,它的访问属性可以受到类的严格控制,对于公有的静态函数成员函数,可以通过类名或对象名来调用,但一般情况下建议用对象名来引用静态函数成员(真的吗?)。注意,一般的成员函数只能通过对象名来调用。
    由于一个类的静态成员函数只有一个拷贝,因此它访问对象的数据何函数使受到了限制。静态成员函数可以直接访问该类的静态数据成员。而访问非静态数据成员,必须通过参数传递方式得到对象名,然后通过对象名来访问。可以看到,通过静态函数成员访问非静态成员使相当麻烦的,一般的使用中,它主要用来访问全局变量或同一个类中的静态数据成员,特别是和后者一起使用,达到对同一个类中对象之间共享的数据进行维护的目的。
    构造函数不可以定义为static看了上面,应该可以理解原因。

    注意,由于static不是函数类型中的一部分,所以在类定义之外定义静态成员函数时不使用static,在类中定义的静态成员函数是内联的。

    一般来说,通过成员名限定比使用对象名访问静态成员要好。因为静态成员不是对象的成员。

    静态成员可以被继承,这时,基类对象和派生类的对象共享该静态成员,除此之外,在类等级中对静态成员的其他特性(例如,静态成员在派生类中的访问权限,在派生类中重载成员函数等)的分析与一般成员类似。

    静态成员函数不能被申明为虚函数,静态成员具有外部连接属性,static仅有的含义是使该成员为该类的所有对象共享。

    类中的任何成员函数都可以访问静态成员,但静态成员函数只能通过对象名(或指向对象的指针)访问该对象的非静态成员,因为静态成员函数没有this 指针。


    虚函数必须是非静态成员函数
    构造函数不可以定义为static

    展开全文
  • 静态函数可以分为全局静态函数和类的静态成员函数。 Static关键字 在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份...

    静态函数
    用static声明的函数是静态函数。静态函数可以分为全局静态函数类的静态成员函数

    Static关键字
    在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化对于该类的所有对象来说,static成员变量只有一份
    用static声明的方法是静态方法,在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。
    静态方法不再是针对于某个对象调用,所以不能访问非静态成员。

    可以通过对象引用或类名(不需要实例化)访问静态成员

    C++类静态数据成员与类静态成员函数
    函数调用的结果不会访问或者修改任何对象(非static)数据成员
    ,这样的成员声明为静态成员函数比较好。且如果static int func(....)不是出现在类中,则它不是一个静态成员函数,只是一个普通的全局函数,只不过由于static的限制,它只能在文件所在的编译单位内使用,不能在其它编译单位内使用。
    静态成员函数的声明除了在类体的函数声明前加上关键字static,以及不能声明为const或者volatile之外,与非静态成员函数相同。出现在类体之外的函数定义不能制定关键字static。
    静态成员函数没有this指针

    在没有讲述本章内容之前如果我们想要在一个范围内共享某一个数据,那么我们会设立全局对象,但面向对象的程序是由对象构成的,我们如何才能在类范围内共享数据呢?

    这个问题便是本章的重点:声明为static的类成员或者成员函数便能在类的范围内共同享我们把这样的成员称做静态成员和静态成员函数。

    下面我们用几个实例来说明这个问题,类的成员需要保护,通常情况下为了不违背类的封装特性,我们是把类成员设置为protected(保护状态)的,但是我们为了简化代码,使要说明的问题更为直观,更容易理解,我们在此处都设置为public。

    以下程序我们来做一个模拟访问的例子,在程序中,每建立一个对象我们设置的类静态成员变自动加一,代码如下:

    1. #include <iostream>  
    2. using namespace std;  
    3.   
    4. class Internet  
    5. {  
    6. public:  
    7.      Internet(char *name,char *address)  
    8.      {  
    9.          strcpy(Internet::name,name);  
    10.          strcpy(Internet::address,address);  
    11.          count++;  
    12.      }   
    13.   
    14.      static void Internet::Sc()//静态成员函数  
    15.      {  
    16.          cout<<count<<endl;  
    17.      }  
    18.   
    19.      Internet &Rq();   
    20.   
    21. public:  
    22.      char name[20];  
    23.      char address[20];  
    24.      static int count;//这里如果写成static int count=0;就是错误的  
    25. };  
    26.   
    27. Internet& Internet::Rq()//返回引用的成员函数  
    28. {  
    29.      return *this;  
    30. }  
    31.   
    32. int Internet::count = 0;//静态成员的初始化  
    33.   
    34. void vist()  
    35. {  
    36.      Internet a1("中国软件开发实验室","www.cndev-lab.com");  
    37.      Internet a2("中国软件开发实验室","www.cndev-lab.com");  
    38. }   
    39.   
    40. void fn(Internet &s)  
    41. {  
    42.      cout<<s.Rq().count;  
    43. }  
    44.   
    45. void main()  
    46. {  
    47.      cout<<Internet::count<<endl;//静态成员值的输出  
    48.      vist();  
    49.      Internet::Sc();//静态成员函数的调用  
    50.      Internet b("中国软件开发实验室","www.cndev-lab.com");  
    51.      Internet::Sc();  
    52.      fn(b);  
    53.      cin.get();  
    54. }  



    上面代码我们用了几种常用的方式建立对象,当建立新对象并调用其构造函数的时候,静态成员cout便运行加1操作,静态成员的初始化应该在主函数调用之前,并且不能在类的声明中出现,通过运行过程的观察我们发现,静态成员count的状态并不会随着一个新的对象的新建而重新定义,尽而我们了解到类的静态成员是属于类的而不是属于哪一个对象的,所以静态成员的使用应该是类名称加域区分符加成员名称的,在上面的代码中就是Internet::count,虽然我们仍然可以使用对象名加点操作符号加成员名称的方式使用,但是不推荐的,静态类成员的特性就是属于类而不专属于某一个对象。

    静态成员函数的特性类似于静态成员的使用,同样与对象无关,调用方法为类名称加域区分符加成员函数名称,在上面的代码中就是Internet::Sc();静态成员函数由于与对象无关系,所以在其中是不能对类的普通成员进行直接操作的。

    如果上面的 static void Internet::Sc()修改成为:

    1. static void Internet::Sc()//静态成员函数  
    2. {  
    3.     cout<<name<<endl;//错误  
    4.      cout<<count<<endl;  
    5. }  



    静态成员函数与普通成员函数的差别就在于缺少this指针,没有这个this指针自然也就无从知道name是哪一个对象的成员了。

    根据类静态成员的特性我们可以简单归纳出几点,静态成员的使用范围:
    1.用来保存对象的个数。
    2.作为一个标记,标记一些动作是否发生,比如:文件的打开状态,打印机的使用状态,等等。
    3.存储链表的第一个或者最后一个成员的内存地址。

    为了做一些必要的练习,深入的掌握静态对象的存在的意义,我们以前面的结构体的教程为基础,用类的方式描述一个线性链表,用于存储若干学生的姓名,代码如下:

    1. #include <iostream>  
    2. using namespace std;  
    3.   
    4. class Student  
    5. {  
    6. public:  
    7.      Student (char *name);  
    8.      ~Student();  
    9.   
    10. public:  
    11.      char name[30];  
    12.      Student *next;  
    13.      static Student *point;  
    14. };  
    15.   
    16. Student::Student(char *name)  
    17. {  
    18.      strcpy(Student::name,name);  
    19.      this->next=point;  
    20.      point=this;  
    21. }  
    22.   
    23. Student::~Student ()//析构过程就是节点的脱离过程  
    24. {  
    25.      cout<<"析构:"<<name<<endl;  
    26.   
    27.      if(point==this)  
    28.      {  
    29.          point=this->next;  
    30.          cin.get();  
    31.          return;  
    32.      }  
    33.   
    34.      for(Student *ps=point;ps;ps=ps->next)  
    35.      {  
    36.          if(ps->next==this)  
    37.          {  
    38.          cout<<ps->next<<""<<this->next<<endl;  
    39.          ps->next=next;//=next也可以写成this->next;  
    40.          cin.get();  
    41.          return;  
    42.          }  
    43.      }  
    44.   
    45.      cin.get();  
    46. }  
    47.   
    48. Student* Student::point=NULL;  
    49. void main()  
    50. {  
    51.      Student *c = new Student("marry");  
    52.      Student a("colin");  
    53.      Student b("jamesji");  
    54.      delete c;  
    55.      Student *fp=Student::point;  
    56.      while(fp!=NULL)  
    57.      {  
    58.          cout<<fp->name<<endl;  
    59.          fp=fp->next;  
    60.      }  
    61.   
    62.      cin.get();  
    63. }   
    64.   
    65.   
    66. <span style="font-size:14px;">从上面的代码来看,原来单纯结构化编程需要的一个链表进入全局指针在这里被类的静态成员指针所替代(类的静态成员完全可以替代全局变量),这个例子的理解重点主要是要注意观察类成员的析构顺序,通过对析构顺序的理解,使用析构函数来进行节点的脱链操作。  
    67.   
    68. <strong><span style="color:maroon;">为什么虚函数必须是非静态成员函数</span></strong>  
    69. 如果定义为虚函数,那么它就是动态绑定的,也就是在派生类中可以被覆盖的,这与静态成员函数的定义本身就是相矛盾的。  
    70.   
    71. ==  
    72. 主要有两个作用:   
    73.      1、管理静态数据成员;   
    74.      2、提供类范围的功能,即不需要对象来实现的功能。   
    75. <strong><span style="color:red;">比如Symbian</span>中的NewL/LC方法就是static的</strong>  
    76.   
    77. ==  
    78. 使用static关键字声明的函数成员是静态的,静态成员函数同样也属于整个类,由同一个类的所有对象共同维护,为这些对象所共享。  
    79.   
    80. 作为成员函数,它的访问属性可以受到类的严格控制,对于公有的静态函数成员函数,可以通过类名或对象名来调用,但一般情况下建议用对象名来引用静态函数成员<strong><span style="color:blue;">(真的吗?)</span></strong>。注意,一般的成员函数只能通过对象名来调用。  
    81. 由于一个类的静态成员函数只有一个拷贝,因此它访问对象的数据何函数使受到了限制。静态成员函数可以直接访问该类的静态数据成员。而<strong>访问非静态数据成员,必须通过参数传递方式得到对象名,然后通过对象名来访问</strong>。可以看到,通过静态函数成员访问非静态成员使相当麻烦的,一般的使用中,它主要用来访问全局变量或同一个类中的静态数据成员,特别是和后者一起使用,达到对同一个类中对象之间共享的数据进行维护的目的。  
    82. <strong><span style="color:red;">构造函数不可以定义为static</span>,</strong>看了上面,应该可以理解原因。  
    83.   
    84. 注意,由于static不是函数类型中的一部分,所以在类定义之外定义静态成员函数时不使用static,在类中定义的静态成员函数是内联的。  
    85.   
    86. 一般来说,通过成员名限定比使用对象名访问静态成员要好。因为静态成员不是对象的成员。  
    87.   
    88. <strong><span style="color:red;">静态成员可以被继承</span></strong>,这时,基类对象和派生类的对象共享该静态成员,除此之外,在类等级中对静态成员的其他特性(例如,静态成员在派生类中的访问权限,在派生类中重载成员函数等)的分析与一般成员类似。  
    89.   
    90. <strong><span style="color:red;">静态成员函数不能被申明为虚函数</span></strong>,静态成员具有外部连接属性,static仅有的含义是使该成员为该类的所有对象共享。  
    91.   
    92. <strong>类中的任何成员函数都可以访问静态成员,但静态成员函数只能通过对象名(或指向对象的指针)访问该对象的非静态成员,因为静态成员函数没有this 指针。</strong></span><strong>  
    93.   
    94. <span style="color:#339966;">  
    95. </span><strong><span style="font-size:14px;color:#ff6600;">虚函数必须是非静态成员函数</span></strong></strong><span style="color:#ff6600;">  
    96. </span><strong><span style="font-size:14px;color:#ff6600;">构造函数不可以定义为static</span></strong>  
    为什么虚函数必须是非静态成员函数 构造函数能为static吗?

    转载于:https://www.cnblogs.com/qianggezhishen/p/7349496.html

    展开全文
  • 静态函数

    2011-11-04 00:44:00
    为什么虚函数必须是非静态成员函数 构造函数能为...静态函数可以分为全局静态函数和类的静态成员函数。 Static关键字 在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始...

    为什么虚函数必须是非静态成员函数 构造函数能为static吗?

    作者:肥仔 来源:C++博客 发布时间:2009-08-19 13:25 阅读:260 次 原文链接 [收藏]


    静态函数
    用static声明的函数是静态函数。静态函数可以分为全局静态函数和类的静态成员函数。

    Static关键字
    在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份。
    用static声明的方法是静态方法,在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。
    静态方法不再是针对于某个对象调用,所以不能访问非静态成员。
    可以通过对象引用或类名(不需要实例化)访问静态成员

    C++类静态数据成员与类静态成员函数
    函数调用的结果不会访问或者修改任何对象(非static)数据成员,这样的成员声明为静态成员函数比较好。且如果static int func(....)不是出现在类中,则它不是一个静态成员函数,只是一个普通的全局函数,只不过由于static的限制,它只能在文件所在的编译单位内使用,不能在其它编译单位内使用。
    静态成员函数的声明除了在类体的函数声明前加上关键字static,以及不能声明为const或者volatile之外,与非静态成员函数相同。出现在类体之外的函数定义不能制定关键字static。
    静态成员函数没有this指针。

    在没有讲述本章内容之前如果我们想要在一个范围内共享某一个数据,那么我们会设立全局对象,但面向对象的程序是由对象构成的,我们如何才能在类范围内共享数据呢?

    这个问题便是本章的重点:声明为static的类成员或者成员函数便能在类的范围内共同享,我们把这样的成员称做静态成员和静态成员函数。

    下面我们用几个实例来说明这个问题,类的成员需要保护,通常情况下为了不违背类的封装特性,我们是把类成员设置为protected(保护状态)的,但是我们为了简化代码,使要说明的问题更为直观,更容易理解,我们在此处都设置为public。

    以下程序我们来做一个模拟访问的例子,在程序中,每建立一个对象我们设置的类静态成员变自动加一,代码如下:

    #include <iostream>
    using namespace std;

    class Internet
    {
    public:
    Internet(char *name,char *address)
    {
    strcpy(Internet::name,name);
    strcpy(Internet::address,address);
    count++;
    }

    static void Internet::Sc()//静态成员函数
    {
    cout<<count<<endl;
    }

    Internet &Rq();

    public:
    char name[20];
    char address[20];
    static int count;//这里如果写成static int count=0;就是错误的
    };

    Internet& Internet::Rq()//返回引用的成员函数
    {
    return *this;
    }

    int Internet::count = 0;//静态成员的初始化

    void vist()
    {
    Internet a1("中国软件开发实验室","www.cndev-lab.com");
    Internet a2("中国软件开发实验室","www.cndev-lab.com");
    }

    void fn(Internet &s)
    {
    cout<<s.Rq().count;
    }

    void main()
    {
    cout<<Internet::count<<endl;//静态成员值的输出
    vist();
    Internet::Sc();//静态成员函数的调用
    Internet b("中国软件开发实验室","www.cndev-lab.com");
    Internet::Sc();
    fn(b);
    cin.get();
    }

    上面代码我们用了几种常用的方式建立对象,当建立新对象并调用其构造函数的时候,静态成员cout便运行加1操作,静态成员的初始化应该在主函数调用之前,并且不能在类的声明中出现,通过运行过程的观察我们发现,静态成员count的状态并不会随着一个新的对象的新建而重新定义,尽而我们了解到类的静态成员是属于类的而不是属于哪一个对象的,所以静态成员的使用应该是类名称加域区分符加成员名称的,在上面的代码中就是Internet::count,虽然我们仍然可以使用对象名加点操作符号加成员名称的方式使用,但是不推荐的,静态类成员的特性就是属于类而不专属于某一个对象。

    静态成员函数的特性类似于静态成员的使用,同样与对象无关,调用方法为类名称加域区分符加成员函数名称,在上面的代码中就是Internet::Sc();静态成员函数由于与对象无关系,所以在其中是不能对类的普通成员进行直接操作的。

    如果上面的 static void Internet::Sc()修改成为:
    static void Internet::Sc()//静态成员函数
    {
    cout<<name<<endl;//错误
    cout<<count<<endl;
    }

    静态成员函数与普通成员函数的差别就在于缺少this指针,没有这个this指针自然也就无从知道name是哪一个对象的成员了。

    根据类静态成员的特性我们可以简单归纳出几点,静态成员的使用范围:
    1.用来保存对象的个数。
    2.作为一个标记,标记一些动作是否发生,比如:文件的打开状态,打印机的使用状态,等等。
    3.存储链表的第一个或者最后一个成员的内存地址。

    为了做一些必要的练习,深入的掌握静态对象的存在的意义,我们以前面的结构体的教程为基础,用类的方式描述一个线性链表,用于存储若干学生的姓名,代码如下:

    #include <iostream>
    using namespace std;

    class Student
    {
    public:
    Student (char *name);
    ~Student();

    public:
    char name[30];
    Student *next;
    static Student *point;
    };

    Student::Student(char *name)
    {
    strcpy(Student::name,name);
    this->next=point;
    point=this;
    }

    Student::~Student ()//析构过程就是节点的脱离过程
    {
    cout<<"析构:"<<name<<endl;

    if(point==this)
    {
    point=this->next;
    cin.get();
    return;
    }

    for(Student *ps=point;ps;ps=ps->next)
    {
    if(ps->next==this)
    {
    cout<<ps->next<<""<<this->next<<endl;
    ps->next=next;//=next也可以写成this->next;
    cin.get();
    return;
    }
    }

    cin.get();
    }

    Student* Student::point=NULL;
    void main()
    {
    Student *c = new Student("marry");
    Student a("colin");
    Student b("jamesji");
    delete c;
    Student *fp=Student::point;
    while(fp!=NULL)
    {
    cout<<fp->name<<endl;
    fp=fp->next;
    }

    cin.get();
    }

    从上面的代码来看,原来单纯结构化编程需要的一个链表进入全局指针在这里被类的静态成员指针所替代(类的静态成员完全可以替代全局变量),这个例子的理解重点主要是要注意观察类成员的析构顺序,通过对析构顺序的理解,使用析构函数来进行节点的脱链操作。

    为什么虚函数必须是非静态成员函数
    如果定义为虚函数,那么它就是动态绑定的,也就是在派生类中可以被覆盖的,这与静态成员函数的定义本身就是相矛盾的。

    ==
    主要有两个作用:
    1、管理静态数据成员;
    2、提供类范围的功能,即不需要对象来实现的功能。
    比如Symbian中的NewL/LC方法就是static的

    ==
    使用static关键字声明的函数成员是静态的,静态成员函数同样也属于整个类,由同一个类的所有对象共同维护,为这些对象所共享。

    作为成员函数,它的访问属性可以受到类的严格控制,对于公有的静态函数成员函数,可以通过类名或对象名来调用,但一般情况下建议用对象名来引用静态函数成员(真的吗?)。注意,一般的成员函数只能通过对象名来调用。
    由于一个类的静态成员函数只有一个拷贝,因此它访问对象的数据何函数使受到了限制。静态成员函数可以直接访问该类的静态数据成员。而访问非静态数据成员,必须通过参数传递方式得到对象名,然后通过对象名来访问。可以看到,通过静态函数成员访问非静态成员使相当麻烦的,一般的使用中,它主要用来访问全局变量或同一个类中的静态数据成员,特别是和后者一起使用,达到对同一个类中对象之间共享的数据进行维护的目的。
    构造函数不可以定义为static,看了上面,应该可以理解原因。

    注意,由于static不是函数类型中的一部分,所以在类定义之外定义静态成员函数时不使用static,在类中定义的静态成员函数是内联的。

    一般来说,通过成员名限定比使用对象名访问静态成员要好。因为静态成员不是对象的成员。

    静态成员可以被继承,这时,基类对象和派生类的对象共享该静态成员,除此之外,在类等级中对静态成员的其他特性(例如,静态成员在派生类中的访问权限,在派生类中重载成员函数等)的分析与一般成员类似。

    静态成员函数不能被申明为虚函数,静态成员具有外部连接属性,static仅有的含义是使该成员为该类的所有对象共享。

    类中的任何成员函数都可以访问静态成员,但静态成员函数只能通过对象名(或指向对象的指针)访问该对象的非静态成员,因为静态成员函数没有this 指针

    文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/3_program/c++/cppjs/20091209/184414.html

    展开全文
  • c++的虚函数

    2020-03-19 22:02:41
    文章目录c++的虚函数虚函数的作用?虚函数的使用方法?虚函数和纯虚函数的区别?多态如何实现?为什么基类的析构函数要用虚函数?为什么c++默认的析构函数不是虚函数?...静态函数不能是虚函数 (因为它没有t...
  • 静态成员函数不可以是虚函数静态函数是属于类的,不属于对象本身,自然无法有自己的虚函数表指针。 不能。因为静态成员函数是可以通过类名直接调用的,而虚函数必须通过对象调用,这样才可以确定到底调用哪个类中...
  • 首先我们先做个例子试试看可以吗? class A{ public : A(){}; ~A() = default; static virtual void test() { } }; int main() { A a; return 0; ...首先的话,静态函数是不和任何类对象或...
  • inline函数

    2016-04-11 18:52:03
    例如C++中,类的成员函数默认的都是内联函数,但是为什么又能是虚函数呢??? 不是说内联函数不能为虚函数吗??这不是矛盾吗?? 还记得在使用函数指针的时候,如果是普通的函数,函数的函数名和&函数名都是一样...
  • 1.静态成员和非静态成员的区别?...11.可以使用抽象函数重写基类中的虚函数吗? 12.密封类可以虚函数吗? 13.什么属性访问器? 14.abstract 可以和 virtual 一起使用吗?可以和 override 一起使用吗?
  • 上一篇我们简单认识了C++的多态, 这次我们来看看多态的底层机制和原理. 不多哔哔, 直接开始. 文章目录虚函数表(虚表)和虚表指针1....3. 构造函数可以是虚函数吗? 虚函数表(虚表)和虚表指针 1. 虚表和虚表指.
  • 继承&多态/面试题目录:一.继承相关面试题1....6.构造函数可以是虚函数吗?7.析构函数可以是虚函数吗?什么场景下是?8.对象访问普通函数快还是虚函数快?9.虚函数表在什么时候生成?存在于哪里?10.虚继承.
  • C++面向对象知识 内存字节对齐 面向对象三大特性 双冒号、using和namespace 内联函数和函数重载 虚函数可以是内联函数吗 构造函数/析构函数 拷贝构造函数与深浅拷贝 只在堆上/栈上创建对象 ...静态函数可以是虚
  • C++多态面试题汇总

    2020-09-04 10:17:14
    静态成员可以是虚函数吗? 不能,因为静态成员函数中没有this指针,使用::成员函数的嗲用用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表。 因为: 首先什么是static静态成员函数?静态成员函数不属于...
  • 多态常见的面试题

    2019-09-26 21:31:45
    inline函数可以是虚函数吗? 答:不能,因为inine函数没有地址,无法把地址放到虚函数表里 静态成员可以是虚函数吗? 答:不能,因为静态成员没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以...
  • C++基础:多态性

    2020-10-28 14:33:16
    构造函数、内联函数、静态成员函数可以是虚函数吗?为什么需要虚继承?虚继承实现原理是什么?总结 https://github.com/jxingm/Interview-Notes/blob/master/c%2B%2B/多态 虚函数 虚函数表.pdf 介绍下多态 C++的...
  • C++知识点

    2021-05-06 15:54:40
    基础 static关键字的认识 C++和C的区别 说一说隐式类型转换 C++中4种cast转换 ...为什么析构函数必须是虚函数?为什么 C++默认的析构函数不是虚函数 fork函数 可以在子线程里执行fork操作吗 fork、
  • 构造函数可以是虚函数吗 析构函数可以是虚函数吗 有哪几种强制类型转换,使用场景 虚函数表存放的内容 多继承的优缺点 全局变量和静态变量区别 volatile 关键字的使用 泛型的概念 C++ 内存分区 C++11新特性 左值和...
  • C++面试题之问题归纳

    2020-09-11 18:19:14
    2.构造函数可以是虚函数吗,为什么? 3.析构函数可以是虚函数吗,什么时候必须为虚函数,为什么? 4.子类析构要调用父类的析构函数吗? 5.C++空类默认有哪些成员函数(提示6种)? 6.什么情况下需要调用拷贝构造函数...
  • 内联函数,构造函数,静态成员函数可以是虚函数吗? 构造函数中可以调用虚函数吗? 为什么需要虚继承?虚继承实现原理解析, C ++内存分配机制 指针 迭代器与普通指针有什么区别 C ++的智能指针及其
  • Linda面试题-详解

    2010-10-14 00:02:00
    待解答第四题:析构函数可以是虚函数吗? 待解答第五题:const 在什么时候使用? 待解答第六题:虚函数与纯虚函数的区别?1.C++虚函数与纯虚函数用法与区别,.虚函数和纯虚函数可以定义在同一个类(class)中,含有纯虚...
  • 7、virtual函数可以是static吗?8、构造、析构函数包含函数可以有virtual函数?二、多态性1、C++的多态性2、静态绑定和动态绑定3、模板类?4、模板类中可以使用虚函数吗? 析构函数、构造函数、虚函数相关问题 一、...
  • 构造函数可以是虚函数吗? 构造函数、析构函数、虚函数可否内联,有何意义? new delete 与 malloc free区别? 空类 sizeof 为什么是1? 4个显示强制类型转换? 为什么一般要定义析构函数为虚析构函数? 静态...
  • 1,静态成员函数可以声明为虚函数吗? 2,派生类构造函数对基类构造函数的调用顺序就是基类构造函数的执行顺序,这句话错在了哪里?真相什么样的?
  • 百题面试题集锦

    2021-05-22 08:42:08
    2. 构造函数可以是虚函数吗?2.1. C++类有继承时,析构函数必须为虚函数3. dynamic_cast的实现原理4. vector怎么删除重复的元素5. 反转链表6. LRU7.1 静态多态和动态多态是如何实现的?7.2 多态性指的是什么?7.3 ...
  • C++基本概念 ...动态多态指的是虚函数 多态https://blog.csdn.net/xy913741894/article/details/52939323 2什么是虚函数?什么是纯虚函数? 3 继承时哪些成员可以继承 private不可以,public和pr...

空空如也

空空如也

1 2 3 4
收藏数 74
精华内容 29
关键字:

静态函数可以是虚函数吗