【C++学习】语法速成3

文章目录

      • 析构函数
      • 构造函数和析构函数的应用
      • 静态成员变量和静态成员函数
      • 成员对象和封闭类
      • 友元
      • this指针
      • 常量对象、常量成员函数和常引用

析构函数

构造函数主要用来初始化对象,析构函数主要用来善后对象的消亡。

特点:

  • 名字与类名相同(为了区别构造函数在前面加~)
  • 没有参数和返回值
  • 一个类最多只有一个析构函数

对象消亡时,析构函数自动被调用,在对象消亡前做一些善后工作,比如释放分配的空间。

在定义类的时候如果没有写析构函数,则编译器会自动生成缺省析构函数(并不会做什么事)。

class String
{
	private:
		char * p;
	public:
		String()
		{
			p=new char[10];
		}
		~ String();		//定义析构函数
};
String::~ String()
{
	delete [] p;	//释放动态内存
}

对象数组的生命周期结束时,对象数组的每个元素的析构函数都会被调用。

使用delete运算也会导致析构函数被调用。

Ctest * pTest;
pTest = new Ctest;		//构造函数调用
delete pTest;		//析构函数调用
pTest = new Ctest[3];	//构造函数调用3次
delete [] pTest;		//析构函数调用3次

构造函数和析构函数的应用

class Demo
{
	int id;
	public:
		Demo(int i)
		{
			id=i;
			cout<<"id="<

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

  • 在成员变量和成员函数之前加上static就变成了静态成员变量和静态成员函数。
class CRectangle
{
	private:
		int w,h;
		static int nTotalArea;		//静态成员变量
		static int nTotalNumber;
	public:
		CRectangle(int w_,int h_);
		~CRectangle();
		static void PrintToal();	//静态成员函数
};
  • 静态成员变量为所有对象共享。(sizeof函数不会计算静态成员变量)

  • 静态成员函数并不具体作用于某个对象。

  • 静态成员不需要通过对象就能访问。

访问静态成员方法:

CRectangle::PrintTotal();		//不用通过具体对象

CRectangle r;		//也可以构造对象后通过对象访问
r.PrintTotal();		

CRectangle * p=&r;	//通过指针访问
p->PrintTotal();

CRectangle & ref = r;		//通过引用访问
int n = ref.nTotalNubmber;

静态成员变量本质上是全局变量,哪怕没有对象,静态成员变量也存在。

静态成员函数本质上是全局函数。

class CRectangle
{
	private:
		int w,h;
		static int nTotalArea;		//静态成员变量
		static int nTotalNumber;
	public:
		CRectangle(int w_,int h_);
		~CRectangle();
		static void PrintToal();	//静态成员函数
};
CRectangle::CRectangle(int w_,int h_)		//构造函数
{
	w=w_;
	h=h_;
	nTotalNumber ++;
	nToalArea += w*h;
}
CRectangle::~CRectangle()		//析构函数
{
	nTotalNumber --;
	nTotalArea -= w*h;
}
void CRectangle::PrintTotal()
{
	cout<
  • 静态成员函数中,不能访问非静态成员变量,不能调用非静态成员函数。(不清楚非静态成员变量属于哪一个类)

  • 上面的代码没有写复制构造函数,肯会造成返回CRectangle类对象的时候,系统调用默认的复制构造函数,造成没有加nTotalNumber和nTotalArea。

成员对象和封闭类

  • 成员对象:一个类的成员变量是另一个类的对象
  • 包含成员对象的类叫做封闭类
class CTyre
{
	private:
		int radius;
		int width;
	public:
		CTyre(iny r,int w):radius(r),width(w){}		//初始化列表(新方式初始化)
};
class CEngine
{
};
class CCar
{
	private:
		int price;
		CTyre tyre;
		CEngine engine;
	public:
		CCar(int p,int tr,int tw);
};
CCar::CCar(int p,int tr,int tw):price(p),tyre(tr,w)		//初始化列表
{

};
int main()
{
	CCar car(20000,17,225);		//价格20000,19半径,225宽度
	return 0;
}

如果上面的CCar类没有定义构造函数的话,编译器不知道CCar里的tyre是如何初始化的,会导致编译出错(engine成员对象没问题,因为它使用默认构造函数)。

  • 初始化列表:类名::构造函数(参数表):成员变量1(参数表),成员变量2(参数表),……

生成封闭类对象时:首先执行所有对象的构造函数(与在封闭类中说明顺序一致,与初始化列表中的出现顺序无关),然后执行封闭类的构造函数。

封闭类对象消亡时:首先执行封闭类的析构函数,然后执行成员对象的析构函数。

即析构函数与构造函数的调用顺序相反,先构造的后消亡。

友元

友元分为:

  • 友元函数
  • 友元类

一个类的友元函数可以访问该类的私有成员

class CCar;		//提前声明,方便后面CDriver类使用
class CDriver
{
    public:
    	void Modify(CCar * pCar);	//改装汽车
};
class CCar
{
    private:
    	int price;
    friend int MostExpensiveCar(CCar cars[],int total);		//声明友元函数
    friend void CDriver::ModifyCar(CCar * pCar); //声明友元函数,使ModifyCar()也可以访问
};
void CDriver::ModifyCar(CCar * pCar)
{
    pCar->price += 1000;	//改装汽车后价值增加
}
int MostExpensiveCar(CCar cars[],int total)
{
    int tmpMax = -1;
    for (int i=0;itmpMax)
            tmpMax=cars[i].price;
    return tempMax;
}
int main()
{
    return 0;
}

除了友元函数,还可以定义一个类为另一个类的友元。

A是B的友元类,则A的成员函数可以访问B的私有成员。

class CCar
{
	private:
		price;
	friend class CDriver;
};
class CDriver
{
	public:
		CCar myCar;
		void ModifyCar()
		{
			myCar.price += 1000;
		}
};
int main()
{
	return 0;
}

this指针

早期编译C++程序时需要将C++程序翻译成C程序,会把成员函数变成全局函数,其中全局函数会比成员函数多一个this指针。

翻译过程示例:

//C++程序
class CCar
{
    public:
    	int price;
        void SetPrice(int p);
};
void CCar::SetPrice(int p)
{
    price=p;
}
int main()
{
    CCar car;
    car.SetPrice(20000);
    return 0;
}
//C程序
struct CCar
{
    int price;
};
void SetPrice(struct CCar * this,int p)	//相比成员函数加了个this指针
{
    this->price=p;
}
int main()
{
    struct CCar car;
    SetPrice(&car,20000);
    return 0;
}

下面的程序需要运用this指针来理解

class A
{
	int i;
    public: void Hello(){cout<<"hello"<Hello();		//但成员函数Hello翻译为C程序后,并没有使用到p,所以可以这样使用
}

静态成员函数中不能使用this指针!

因为静态成员函数并不作用于某个对象!

因此,静态成员函数的真实的参数个数就是程序中写出的参数个数。

常量对象、常量成员函数和常引用

  • 常量对象

如果不希望某个对象的值被改变,则定义该对象的时候可以在前面加上const关键字。

class Demo
{
	private:
		int value;
	public:
		void SetValue(){}
};
const Demo Obj;	//常量对象
  • 常量成员函数

在类的成员函数说明后面可以加上const关键字,则该成员函数称为常量成员函数。

常量成员函数执行期间不应修改其作用的对象。因此,在常量成员函数中不能修改成员变量的值(静态成员变量除外),也不能调用同类的非常量成员函数(静态成员函数除外)。

class Sample
{
    public:
    	int value;
    	void GetValue() const;
    	void func(){};
    	Sample(){}
};
void Sample::GetValue() const
{
    value=0;	//wrong,不能修改成员变量的值
    func();		//wrong,不能调用非常量成员函数
}
int main()
{
    const Smaple o;
    o.value=100;	//wrong,常量对象不可被修改
    o.func();		//wrong,常量对象上不能执行非常量成员函数
    o.GetValue();	//OK,可以调用常量成员函数
    return 0;
}

两个成员函数,名字和参数都一样,但是一个是const,一个不是,那么这两个成员函数算重载。

class  CTest
{
    private:
    	int n;
    public:
    	CTest(){n=1;}
    	int GetValue() const {return n;}
    	int GetValue() {return 2*n;}
};
int main
{
	const CTest objTest1;
	CTest objTest2;
	cout<
  • 常引用

在引用前面可以加上const关键字,称为常引用。不能通过常引用修改引用的变量。常用作函数形参。

一般对象作为函数参数使,生成该参数需要调用复制构造函数,效率比较第。如果用指针作为参数,代码又不好看,这时可以用引用作为参数。如:

class Sample
{
	……
};
void PrintObj(Sample & o)
{
	……
}

但对象引用作为函数参数有一定风险性,在函数内若修改了形参o,那么实参也会改变,这时就可以用对象的常引用作为参数,如:

class Sample
{
	……
};
void PrintObj(const Sample & o)
{
	……
}

objTest2;
cout< return 0;
}


* 常引用

在引用前面可以加上const关键字,称为常引用。不能通过常引用修改引用的变量。常用作函数形参。

一般对象作为函数参数使,生成该参数需要调用复制构造函数,效率比较第。如果用指针作为参数,代码又不好看,这时可以用引用作为参数。如:

~~~c++
class Sample
{
	……
};
void PrintObj(Sample & o)
{
	……
}

但对象引用作为函数参数有一定风险性,在函数内若修改了形参o,那么实参也会改变,这时就可以用对象的常引用作为参数,如:

class Sample
{
	……
};
void PrintObj(const Sample & o)
{
	……
}

你可能感兴趣的:(C++学习)