1、C++中可以有不同的数据成员类型,这些成员类型有不同的作用,最常见的数据成员类型分别是:静态数据成员,常量数据成员,引用数据成员以及常量引用数据成员。
1.1 先看静态数据成员。静态数据成员的声明方法是:
class myClass
{
public:
void printCount();
private:
static int count;
};
静态数据成员既可以在类方法内访问静态数据成员,也可以在类方法外部访问静态数据成员。在类方法内部访问静态成员时和使用普通的成员变量没有区别,例如我们可以这样定义printCount()函数:
void printCount()
{
cout<<count<<endl;
count++;
}
当我们在类方法外部访问静态数据成员时,是这么用的(此时,count应该定义为public):
int yourCount=myClass::count;
用法知道了以后就是静态的作用,静态数据成员是所有对象共有的数据成员,所有对象都可对它进行操作。假设myClass有两个对象分别是a和b,a执行myCount()之后,输出的是0,b执行myCount()之后输出的是1,a再执行myCount()之后输出的就是2;
1.2 接下来是常量数据成员。类中的数据成员可以声明为const,意味着在创建并初始化以后,数据成员的值就不能再改变。这是为什么当类定义常量数据成员时我们应该使用构造函数初始化器来初始化数据成员的原因。如果某个常量只适用于类,那么应该使用静态常量数据成员,而不是全局常量。
1.3 接下来是引用数据成员。引用数据成员需要使用构造函数初始化器才能使用,因为如果引用对象不存在,就没办法使用引用,而且引用一旦初始化,就不能改变引用的对象,因此不可能在赋值运算符中对引用赋值。
1.4 最后是常量引用数据成员。这个就是引用数据成员和常量数据成员的结合。值得注意的是,常量引用数据成员只能调用常量方法,不能调用非常量方法。
2、 同样的,C++可以有不同的方法,主要有静态方法,const方法内联方法等等。
2.1 先说静态方法。静态方法是在类中使用staitc修饰的方法,在类定义的时候已经被装载和分配。而非静态方法是不加static关键字的方法,在类定义时没有占用内存,只有在类被实例化成对象时,对象调用该方法才被分配内存。静态方法的定义是这样的:
class myClass
{
public:
static void printCount()
{
cout<<count<<endl;
count++;
}
private:
static int count;
int yourID;
};
可以看到此时printCount()方法被定义为静态方法。静态方法不属于特定对象,因此没有this指针,当用某个特定对象调用静态方法时,静态方法不会访问这个对象的非静态数据成员。实际上,静态方法就像一个普通的函数一样,只不过这个静态方法只能访问类的静态数据成员或者静态方法。使用类的静态方法就像使用静态数据成员一样,在类方法内部,就像普通方法一样,在类方法外部则要使用作用域限定符。
2.2 接下来说const方法。常量对象的值不能改变。如果使用常量对象、常量对象的引用和指向常量对象的指针,编译器将不允许调用对象的任何方法,除非这些方法承诺不改变任何数据成员。为了不改变数据成员,可以用const关键字标记方法本身。
class myClass
{
public:
const void printID()
{
cout<<yourID<<endl;
}
private:
static int count;
int yourID;
};
将方法标记为const,就是与客户代码立下了契约,承诺在方法内部不会改变对象内部的值。如果将实际上修改了数据成员的方法声明为const,编译器将会报错。不能将静态方法声明为const,因为这是多余的。静态方法没有类的实例,因此也就不存在对象内部的值。const的工作原理是将方法内部用到的数据成员都标记为const引用,因此如果试图修改数据成员,编译器就会报错。值得一提的是,非const对象可以调用const方法和非const方法,然而,const对象只能调用const方法。但是有时候我们需要在const方法内部改变一些对对象无关的值,如果我们去修改了,编译器又会认为这样做是错误的,编译就会不通过,这时候我们需要将变量声明为mutable,例如:
class myClass
{
public:
const void printID()
{
cout<<yourID<<endl;
count++;
}
private:
mutable int count=0;
int yourID;
};
每调用一次printID()方法,count就会自增1,我们将count声明为mutable(中文意思:可变的、会变的,就是告诉编译器在const()方法内部允许改变这个值)就可以在const方法内部改变count的值而编译器也会通过。
2.3 再说说 方法重载。我们都知道,一个类可以有多个构造函数,只不过这些构造函数的参数数量或者参数类型应该不一样。在C++中,可以对任何方法这么做,这就是重载。例如:
class myClass
{
public:
void add(int i,int j)
{
cout<<"Two Integers' addition i + j = "<<i+j<<endl;
}
void add(double i,double j)
{
cout<<"Two Doubles' addition i + j = "<<i+j<<endl;
}
};
当我们这样用时:add(1,2),就调用了第一个add方法,当我们使用add(1.0,2.1)时就用了第二个方法。需要注意的是,不应该将返回值的不同作为重载的依据。另外,可以根据const重载方法,也就是说可以编写两个名称相同参数也相同的方法,只不过其中一个是const方法,另一个不是。如果是const对象就调用const方法,如果不是const对象就调用非const方法。重载方法可以被显式的删除,用这种方法禁止调用具有特定参数的成员函数。例如考虑下面的函数:
class myClass{
public:
void foo(int i);
};
我们用这个方法的时候一般这么用foo(1);这个当然是可以运行的,但是foo(1.2)也可以运行,因为1.2这个double类型的数会被强制转换为int类型,这样就运行了,我们可以阻止这种转换,例如:
class myClass{
public:
void foo(int i);
void foo(int i)= delete;
};
通过这一改动,用double做参数调用foo()时,编译器会给出错误提示,而不是将其转换为整数。此外还有,默认参数还有内联方法不赘述了。