【C++易错点总结】类和其他对象的特性

静态成员

静态数据成员

class Sample
{
	int a,b,c;//非静态数据成员 
	static int d;//静态数据成员
}s1,s2,s3; 

静态数据成员的初始化必须在类体外进行。

int Sample::d=10; 

注意
1、如果没有=10,那么静态数据成员的值被初始化为0。
2、变量名前要加类名限定,指定他所属的类

静态数据成员是类的所有对象共享的,而不是某个对象独享的,也可以说静态数据成员是属于类的。

静态数据成员的提出是为了解决对象之间的数据共享问题,一个对象给静态数据成员赋值之后,另一个对象可以读取该值。

静态成员函数

静态成员函数和静态数据成员一样,都是属于类的,而不是属于对象的。

在类体外调用公有静态成员函数:

<类名>::<静态成员函数名> (实参列表)

C++也允许通过对象名调用公有静态成员函数

<对象名>.<静态成员函数名> (实参列表)

同理,如果将一个静态数据成员定义成共有的,在类体外可以通过一下两种方式访问

<类名>::<静态成员成员名>
<对象名>.<静态成员成员名>

注意
如果静态数据成员或静态成员函数是私有的,在类体外不管是通过类名还是通过对象名都不能直接访问。

一般成员函数内部可以访问其他静态成员,而在静态成员函数中,只能直接访问类的其他静态成员,不能直接访问类的非静态成员。如果要想在静态成员函数中访问非静态成员,可以通过参数对象来实现,具体见下例;

#include <iostream>
using namespace std;

class Sample
{
    int a;
    static int b;                       	// 定义私有静态数据成员 
public:
    static int c;                      		// 定义公有静态数据成员 
    Sample(int x) { a = x; b += x; }
    static void disp(Sample s)            // A,定义静态成员函数 
    {
        cout << "a=" << s.a << ", b=" << b << endl;  // B
    }    				// 续前行,访问非静态数据成员和静态数据成员  
};

int Sample::b = 10; 				// C,初始化静态数据成员 
int Sample::c = 20; 				// D,初始化静态数据成员 

int main()
{
    Sample s1(2), s2(3);

    Sample::disp(s1);  		   	// E,可改写为s1.disp(s1);或s2.disp(s1);
    Sample::disp(s2);  		    // F,可改写为s1.disp(s2);或s2.disp(s2);
    cout << "c=" << Sample::c << endl;	
    // G,Sample::c 可改写为 s1.c 或 s2.c
    return 0;
}

友元

友元函数

类有很好的封装性和信息隐蔽性,即只有在类的成员函数中才能直接访问私有成员,在类外不能直接访问私有成员和保护成员(除非有公有函数接口)

这个时候,可以把函数定义为类的友元函数,见A行,这样就可以在友元函数内直接访问类的私有成员。

注意
1、友元函数不是类的成员函数,所以,可以把友元函数放在类的任意段:private、protected、public

2、书写友元函数的时候前面不用加类的限定,直接写friend后面的东西就好。

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

class Point
{
    int x, y;
public:
    Point(int a = 0, int b = 0) : x(a), y(b) { }
    void Show() { cout << "Point(" << x << ',' << y << ")\n"; }
    int Getx() { return x; }
    int Gety() { return y; }
    friend double dist(Point&, Point&);                // A
};

double dist(Point &p1, Point &p2)
{
    return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));//B
}

int main()
{
    Point p1, p2(1, 1);

    cout << dist(p1, p2) << endl;
    return 0;
}

一个类的成员函数作为另一个类的友元函数

#include <iostream>
using namespace std;

class N;     				 // A,类N的引用性说明

class M
{
    int a, b;
public:
    M(int x, int y) { a = x; b = y; }
    void Print(){ cout << "a=" << a << '\t' << "b=" << b << endl; }

    void Setab(N &); 	// B,Setab()是M类的成员函数,其参数是N类对象的引用  
};

class N
{
    int c, d;
public:
    N(int x, int y) { c = x; d = y; }
    void Print() { cout << "c=" << c << '\t' << "d=" << d << endl; }

    friend void M::Setab(N&);	// C,将类M的成员函数Setab()说明成本类的友元函数
};

void  M::Setab(N &obj)			// 类M的成员函数Setab( )是类N的友元函数,
{
    a = obj.c;  				// D,因此在Setab( )中可直接访问类N的私有成员。
    b = obj.d;
}
int main( )
{
    M m(25, 40);
    N n(55, 66);

    cout << "m: "; m.Print();
    cout << "n: "; n.Print();
    m.Setab(n);
    cout << "m: "; m.Print();
    return 0;
}

运行结果:

m: a=25 b=40
n: a=55 d=66
m: a=55 b=66

友元类

当一个类作为另外一个类的友元时,意味着这个类的所有成员函数都是另一个类的成员函数

定义友元类:

class A
{
	friend class B;
}
class B
{
	xxxxxxxx
}

在B类所有成员函数中,均可以直接访问A类的私有成员

#include <iostream>
using namespace std;

class B;     // 类的引用性说明

class A      // 类中默认访问权限是私有的
{
    int x;
    void Disp() { cout << "x=" << x << endl; }   // 私有成员函数 

    friend B;                               			// 将B类说明成A类的友元类
};

class B
{
public:
    void Set(int n)
    {
        A a;
        a.x = n;     //可访问A类对象的私有数据成员x
        a.Disp();    //可访问A类对象的私有成员函数Disp( )
    }
};

int main(void)
{
    B b;
    b.Set(3);
    return 0;
}

运行结果:

x=3

常数据成员和常成员函数

常数据成员

常数据成员的值是常量,不能被修改。

常数据成员的初始化只能在类的构造函数的成员初始化列表中进行。

class Point
{
	int x,y;
	const int color;
public:
	Point(int a=0,int b=0,int c=0):color(c)//构造函数
	{
		x=a;
		y=b;
	}
};

或者也可以写成

Point(int a=0,int b=0,int c=0):x(a),y(b),color(c){}

常成员函数

定义常成员函数的方法是在函数头的尾部、参数的右括号后面加关键字

注意

1、常成员函数只能读取类的数据成员,不能修改(比如不能赋值)

2、一般成员函数(指非const成员函数)可以修改除了常数据成员其他数据成员的值

#include <iostream>
using namespace std;

class Point
{
    int x;			  	// 一般数据成员
    const int y;	  		// 常数据成员
public:
    Point(int a = 0, int b = 0) : x(a), y(b) { }

    int fun()         		// A,一般成员函数
    {
        x = 5;        		// 修改一般数据成员x,合法
        y = 6;        		// 修改常数据成员,	非法
        return x + y;   	// 读取x和y,		合法
    }
    int fun() const   	// B,常成员函数 
    {
        x = 5;        		// 修改一般数据成员x,非法
        y = 6;        		// 修改常数据成员,    非法
        return x + y;   	// 读取x和y,		合法
    }
};

3、const参与重载函数的区分,见上例A行和B行。

4、常对象只能调用长常成员函数

#include <iostream>
using namespace std;

class Point
{
    int x;
    const int y;
public:
    Point(int a = 0, int b = 0) : x(a), y(b) { }
    int fun();
    int fun() const;  			// 类中声明有关键字const 
};
int Point::fun()
{
    return x + y;
}
int Point::fun() const   		// 类外定义也必须有关键字const
{
    return x - y;
}
int main()
{
    Point p1(1, 8);
    const Point p2(1, 8);

    cout << p1.fun() << ',' ;	// p1调用的是第1个fun()函数
    cout << p2.fun() << endl;	// p2调用的是第2个fun()函数
    return 0;
}

5、如果要修改某个常对象数据成员的值,可以将数据成员定义为mutable

6、常成员函数只能调用长成员函数,不能调用非const成员函数。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值