您的位置:首页 > 编程语言 > C语言/C++

C++学习笔记-类1

2013-03-20 15:35 204 查看
1.类作用域和类定义作用域

类定义作用域为包含类定义的花括号语句块,如果没有花括号语句块,则为从类定义开始的全部代码空间。

类作用域仅包括类定义内部和所有其成员函数的定义体。



#include <iostream>
using namespace std;

class X{
public:
	void f1(){
		m = 6;
		f2();
	}
	void f2();
private:
	int m;
};

void X::f2()
{
	cout<<"Data member: "<<m<<endl;  // X::m
	int m = 7;
	cout<<"Local member: "<<m<<endl;  //X::m被隐藏
	cout<<"Data member: "<<X::m<<endl;
}

int main() //此处以下不属于类作用域但属于类定义作用域
{
	X x;
	x.f1();
}


上述代码中的成员函数f1访问了类定义中稍后声明的私有数据m(第16行)和成员函数f2(第14行),这是f1的权利。即使在类定义的外部,其成员函数f2(第18~23行)也可以访问私有数据m,只是敌不过函数体中的局部同名数据m,而遭到隐藏的冷遇,但通过类名空间的::操作,一样可以访问。

2.静态成员

静态数据成员:每个类只有一个静态数据成员实体,每个对象不再有它的副本。



#include <iostream>
#include <string>  //由于cout不支持string类型的数据,所以头文件中应该包括string
using namespace std;

class Student{
	static int number;
	string name;
public:
	Student(string str){
		name = str;
		number++;
	}
	void print() { cout<<name<<"->students are "<<number<<" numbers\n"; }
};

int Student::number = 0; //静态数据成员在类外分配空间和初始化

void fn()
{
	Student s1("Smith");
	Student s2("Randy");
	s1.print();
}

int main()
{
	Student s("Smith");
	fn();
	s.print();
};


整个类中只有一份number拷贝,所有的对象都共享这份拷贝。因此,输出学生总数时,访问的是唯一的静态数据成员,它不会因对象而异了。

定义静态成员的格式不能重复static关键字(第18行),但必须在成员名前冠以类名加域操作符,以表示该成员的类属。如果不将其初始化,则系统将为该成员清0。



3.静态成员函数

将静态成员做成私有的,用静态成员函数去访问静态数据成员是合适的。

#include <iostream>
#include <string>  //由于cout不支持string类型的数据,所以头文件中应该包括string
using namespace std;

class Student{
	static int number;
	string name;
public:
	Student(string str){
		name = str;
		number++;
	}
	static void printNumber(){ cout<<number<<" total numbers\n"; }
	void print() { cout<<name<<"->students are "<<number<<" numbers\n"; }
};

int Student::number = 0; //静态数据成员在类外分配空间和初始化

void fn()
{
	Student s1("Smith");
	Student s2("Randy");
	s1.print();
	s1.printNumber();
}

int main()
{
	Student s("Jenny");
	fn();
	s.print();
	Student::printNumber();
};


静态成员函数并不受对象的牵制,可以用对象名调用静态成员函数,也可以用类名加上域操作符调用静态成员函数,这时候,将它看作是某个名空间的一个函数。

静态成员函数的实现位置与成员函数的实现位置应该是一起的,静态成员函数如果不在类中实现,而在类的外部实现时,类名前应免去static关键字。成员函数的静态性只在类中声明的时候才是必要的。

因为静态成员函数可以不以捆绑对象的形式调用,静态成员函数被调用时,没有当前对象的信息,所以静态成员函数不能访问数据成员,如下:

static void printNumber(){ cout<<name<<number<<" total numbers\n"; }

则编译通不过,error: illegal reference to non-static member 'Student::name。这并不是说它没有访问私有数据访问的权限,如果在静态成员函数中,给它传递一个Student对象:

static void printNumber(Student& s){
		cout<<"My name is "<<s.name<<"\n";
		cout<<s.number<<" total number\n";
	}

那么,访问私有数据便是它的权利。

4.关于增量操作符的重载

一个整型变量的前增量操作的结果与变量值是一致的,而且前增量操作的结果是左值,操作可以连贯。而后增量操作的结果是增量之前的变量值,它是临时变量,当表达式计算工作完成后,该临时变量随即消失,所以变量最终值与后增量结果是错位的。例如:

int a=1, b=1, c=1, d=1;
(++a)++;	//结果a=3
(b++)++;	//结果b=2,(b++)的结果是临时变量,在其上加1随后又抛弃
++(++c);	//结果c=3
++(d++);	//结果d=2,与b相似


在反映对象的前增量操作时,要求参数为对象的引用,返回的仍然是该对象参数的引用:

X& operator++(X& a); //前增量操作符
++a;	//等价于operator++(a); 匹配上述操作符声明


后增量操作符的重载,同样要求参数为对象的引用,因为在调用的上下文中,实参将发生变化,而返回则为临时对象,所以为非引用的对象值。在区分前后增量操作符时,C++做了一个技术处理:

X operator++(X& a, int b);	//后增量操作符
a++;	//等价于operator++(a,1); 匹配上述操作符声明

调用后增量操作符的参数匹配是违背函数参数匹配常规的,编译专门做了特殊处理。

#include <iostream>
#include <iomanip>
using namespace std;

class Time
{
	int hour, minute, second;
public:
	Time (int h , int m , int s ) : hour(h), minute(m), second(s) {}
	friend Time& operator++(Time& a);
	friend Time operator++(Time& a, int);
	friend ostream& operator<<(ostream& o, const Time& t);
};

Time& operator++(Time& a) //友元函数可以直接访问对象的私有成员,但是友元的函数参数中必须有对象才行!前增量操作符
{
	if (!(a.second = (a.second+1)%60) && !(a.minute = (a.minute+1) % 60))
		 a.hour = (a.hour+1)%24;
	return a;
}

Time operator++(Time& a, int)  //后增量操作符
{
	Time t(a);
	if (!(a.second = (a.second+1)%60) && !(a.minute = (a.minute+1) % 60))
		a.hour = (a.hour+1)%24;
	return t;
}

ostream& operator<<(ostream& o, const Time& t)
{
	o<<setfill('0')<<setw(2)<<t.hour<<":"<<setw(2)<<t.minute<<":";
		return o<<setw(2)<<t.second<<"\n"<<setfill(' ');
}

int main()
{
	Time t(11, 59, 58);
	cout<<t++;
	cout<<++t;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: