frankfan的胡思乱想

学海无涯,回头是岸

成员

常成员函数 初始化列表 静态成员

常成员函数

在C++中,被const关键词修饰的对象只能在初始化时赋值,此后不能被修改。并且,对象的成员也不能被修改;

#include <iostream>
using namespace std;
class Node{
public:
  int value;
};
int main(){
  
  const Node node;
  //node.value = 11;编译错误,const对象成员对象无法被修改赋值
  return 0;
}

除了不能直接修改const对象的成员外,也不能通过调用成员函数的方式修改对象的成员

#include <iostream>
using namespace std;
class Node{

public:
  void modify(int v){
    value = v;
  }
private:
  int value;
};
int main(){
	const Node node;
  //node.modify();编译错误,const对象即使使用调用成员函数的方式也不能修改成员
  return 0;
}

const对象无法调用普通成员函数,究其本质原因,在于普通成员函数的__thiscall调用中this指针的类型与const对象不一致

普通成员函数的this指针类型为TypeClass * const this this是常量指针,无法被修改指向,但是能通过this指针修改成员值。而若要能做到无法通过this指针修改成员值,则需要this指针的类型为cosnt TypeClass * const this ,因此普通成员函数不满足要求.

#include <iostream>
using namespace std;
class Node{
public:
  Node(int v = 0):value(v){}
  int GetValue()const{
    return value;//this指针类型为 const Node* const this
  }
private:
  int value;
};
int main(){
  
  //const成员函数,无论是否为const对象都能调用
  const Node node(11);
  cout<<node.GetValue()<<endl;//11
  
  Node noed2(12);
  cout<<node2.GetValue()<<endl;//12
  return 0;
}

初始化列表

C++提供构造函数用来初始化成员,但是如果成员中存在C++类类型的成员,则无法直接在构造函数体内对对象进行初始化(只能进行新创建),此外还有对const成员动态初始化等,因此,C++提供了构造函数的初始化列表语法

#include <iostream>
using namespace std;

class Tnode{
public:
  Tnode(int tnv = 0):tnode(tnv){}
private:
  int tnode;
};

class Node{
public:
  Node(){}
  Node(int v,int _mid,int tnv):value(v),mid(_mid),tnode(tnv){
    //不能在构造函数体内部对const成员赋值,也无法调用对象成员的带参构造函数初始化对象
    //当然,可以这样写,但是会多创建一个无用的临时对象
    tnode = Tnode(12);
  }
private:
  int value;
  const int mid;
  Tnode tnode;
};
int main(){
  
  Node node(11,22,33);
  return 0;
}

初始化列表处理能处理成员的初始化外,也能解决构造函数的相互调用问题

#include <iostream>
using namespace std;
class Node{
public:
  Node(int value,int mid):value(value),mid(mid){}
  //运用已存在的构造函数实现新的构造函数,不能在新的构造函数体内调用已存在的构造函数,那样就成了创建新的临时对象了
  Node(int value):Node(value,0){}
  Node():Node(0,0){}
private:
  int value;
  int mid;
};
int main(){
  Node node;
  Node node2(11);
  Node node3(11,22);
  return 0;
}

关于使用初始化列表对对象成员的初始化,类的成员对象的初始化时机与在初始化列表中的位置无关。类内部的对象成员初始化时机取决于其在源码中的位置。最先定义的对象最先被初始化,后定义的对象被后初始化,这些对象要先于本体对象被初始化,而后于本体对象被析构。

#include <iostream>
using namespace std;

class TTnode{
public:
  TTnode(int v = 0){}
  ~TTnode(){}
};

class Node{
public:
  Node():tnode(11),tnode2(22),tnode3(33){}
private:
  TTnode tnode;
  TTnode tnode2;
  TTnode tnode3;
};

int main(){
  
  //node对象中有3个TTnode对象,node对象与TTnode这3个对象间的构造与析构顺序是
  //构造顺序:tnode、tnode2、tnode3、node
  //析构顺序:node、tnode3、tnode2、tnode
  Node node;//最先构造的最后释放,最后构造的最先释放
  return 0;
}

静态成员与静态成员函数

在C语言中,无论是全局变量还是静态全局变量,其内存都在数据区,并且当进程创建时便存在。内存独一份。

全局变量的作用域是工程项目的所有源文件中,而这就导致全局变量非常容易滥用,从而造成项目的可维护性大打折扣。而C++中,则提供了静态成员这样类型,可以认为是带有命名空间访问受限的全局变量。

C++中的静态成员内存也是在高地址的数据区,与普通全局变量或者静态变量的内存区域并无区别。

#include <iostream>
using namespace std;
class Node{
public:
  static int value;
};

//定义静态成员时初始化时只能在类外部初始化,静态成员必须被初始化,无论创建多少新node对象,静态成员内存value永远只有一份
int Node::value = 0;

int main(){
  
 	Node node1;
  node1.value = 11;
  
  Node node2;
  node2.value = 22;
  
  //value的你内存是数据区中的,独一份,因此不管通过哪个对象对其进行修改,都是修改同一份内存
  cout<<node1.value<<endl;//22
  
  //由于value内存属于全局区,因此对其访问跟对象并没有关系,并不需要通过对象实例去访问静态成员,所以常见的使用方式是直接通过类名进行访问
  Node::value = 11;
	cout<<Node::value<<endl;//11
  
  Node::value = 22;
	cout<<Node::value<<endl;//22
  return 0;
}

静态成员是受限的全局变量,除了需要通过类名进行访问外,还可以设置静态成员的访问权限,这样进一步对其进行了访问限制

#include <iostream>
using namespace std;
class Node{

public:
  void SetValue(int v){
    if(v > 0){
      value = v;
    }
  }
  
  int GetValue(){
    return value;
  }
  
private:
  static int value;
};

int Node::value = 0;

int main(){
  
  //Node::value = 11;编译错误,无法直接访问静态成员,虽然其属于数据区内存,但被private限制了访问,只能通过函数访问
  Node node;
  node.SetValue(11);
  //虽然能通过对象访问value,但是需要先创建node对象,这显然是不合理的
  cout<<node.GetValue()<<endl;//11
  return 0;
}

静态成员函数,无需先创建对象,可以直接通过对象名来调用函数(但无法通过对象来调用静态成员函数,其调用约定 并不相同)

#include <iostream>
using namespace std;
class Node{
public:
  //静态成员函数,并不遵循__thiscall调用约定,也不能通过node对象调用此函数,并没有this指针传入
  static void SetValue(int v){
    if(v > 0){
      value = v;
    }
    
    //demoV = 0;编译错误,静态成员函数内部并没有this指针,因此无法修改对象的成员
  }
  
  static int GetValue(){
    return value;
  }
  
private:
  static int value;
  int demoV;
};

int Node::value = 0;

int main(){
  
  Node node;
  //node.SetValue(11);编译错误,无法通过对象调用静态成员函数
  Node::SetValue(11);
  cout<<Node::GetValue()<<endl;//11
  return 0;
}

通常,静态成员变量配合静态成员函数使用(在某些编程语言中,静态成员变量又被称为类变量,静态成员函数又被称为类方法)

posted on 2021-12-28 00:27  shadow_fan  阅读(277)  评论(0编辑  收藏  举报

导航