对象成员
面向对象“类成员”的分类
定义:面向对象“类”中的数据成员和函数成员统称为“类成员”;
函数成员可细分为:
数据成员依‘存储特征’可分为:
数据成员依‘数据类型’可分为:
类数据成员
普通数据成员
数据成员不能在确定对象之前存在,即实例化之后才存在;
如“int a”,只有在用类型定义(创建)一个变量时才分配空间;
常量数据成员
声明:在类数据成员声明之前添加添加关键字**“const”,** 即把数据成员声明为“常量数据成员”,如下所示:
class X{
const 类型 常量成员名;
……
}
常量数据成员的初始化可以通过构造函数初始化参数列表
静态数据成员
声明:在类数据成员声明之前添加添加关键字**“static”,** 即把数据成员声明为“静态数据成员”,如下所示:
class X{
static 类型 静态成员名;
……
}
静态数据成员的常常在类外定义,有2方式:
使用默认值的方式: 类型 类名::静态成员名;
指定初始值的方式:类型 类名::静态成员名=初始值;
注意事项:
① 在类外定义静态数据成员时,不能加上static限定词;
② 在定义静态数据成员时可以为其指定初始值(第2种形式),若定义时没有指定初值,系统默认初始值为0。
类对象成员
基本概念
类的数据成员一般都是基本数据类型,但也可以是结构、数据、枚举之类的自定义数据类型,还可以是其他类的对象。
如果用其他类的对象作为类的成员,则称之为对象成员。
类对象作成员的形式如下:
class X{
类名1 成员名1;
类名2 成员名2;
……
类名n 成员名n;
};
类对象成员的初始化
可通过构造函数初始化列表中初始化对象成员
包含对象成员类的构造函数的定义形式:
X::X(参数表0): 成员名1(参数表1), ……, 成员名n(参数表n)
//初始化参数列表方式
{
构造函数体;
}
对象成员的构造次序与它们在类中的声明次序相同,与它们在构造函数初始化列表中的次序无关!
class A{
int a;
public:
A(int i=1) :a(i) { cout<<"constructing A:" <<a<<endl; }
};
class B{
int b;
public:
B(int i) :b(i) { cout<<"constructing B:" <<b<<endl; }
};
class C{
A a1,a2;
B b1,b2;
public:
C(int i2,int i3,int i4):b1(i2), b2(i3), a2(i4) { }
};
void main(){
C x(2,3,4);
}
先声明a1,
再声明a2,
再声明b1,
再声明b2,
输出:
constructing A:1
constructing A:4
constructing B:2
constructing B:3
函数成员
声明与定义
函数成员的定义方式,有2种:
(1)在类声明中定义(内置定义 —>内置函数)
class X{……
public:
返回类型 成员函数名(参数列表) {
函数体(函数实现)
}
};
类内定义的函数成员默认为内联函数!
(2)在类声明之外定义(外置定义—> 外置函数)
class X{……
public:
返回类型 成员函数名(参数列表); //声明
};
返回类型 类名X::成员函数名(参数列表){
函数体(函数实现)
类外定义的函数成员要成为内联函数, 需要手动声明!(inline关键字)
常量成员函数
常量成员函数
在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数。
class X{ ……
const 类型 数据成员名; //常量数据成员
返回类型 函数名(参数列表) const; //常量函数
……
};
常量成员函数执行期间不应修改其所作用的对象。因此,在常量成员函数中不能修改成员变量的值
(静态成员变量除外),也不能调用同类的非常量成员函数(静态成员函数除外)。
class Sample
{
public:
int value;
void GetValue() const;
void func() { };
Sample() { }
};
void Sample::GetValue() const
{
value = 0; // wrong 常量成员函数不可修改其所作用的对象,故不可修改成员变量的值
func(); //wrong 常量成员函数不可修改其所作用的对象,故不可调用同类的非常量成员函数
}
int main() {
const Sample o;
o.value = 100; //err.常量对象不可被修改
o.func(); //err.常量对象上面不能执行非常量成员函数
o.GetValue(); //ok,常量对象上可以执行常量成员函数
return 0;
} //在Dev C++中,要为Sample类编写无参构造函数才可以,Visual Studio2010中不需要
只有类的成员函数才能定义为常量成员函数, 普通函数不能定义为常量函数。
(函数)常量参数 与 常量成员函数 两者是有区别的!
double distance(const int& p1); //常量参数
int fun(int t) const; //常量成员函数
前者可出现在任何函数中,而后者只适用于类成员函数;
前者限制“函数对参数的修改”,而后者限制“类成员函数对类数据成员的修改”。
静态成员函数
- 在类成员函数的原型前面加上“static”就将它定义成了静态成员函数。
静态成员函数是属于整个类的!
只能访问属于类的静态成员(包括静态数据成员和静态函数成员),
不能访问非静态成员(包括非静态的数据成员和成员函数)。 - 静态成员函数有两种调用方式
类名::静态成员函数名(参数表);
对象名.静态成员函数名(参数表);
#include <iostream>
using namespace std;
class Book{
private:
char bkName[20];
double price;
static int number; //数目: 静态数据成员
static double totalPrice; //总价: 静态数据成员
public:
Book(char *,double); //构造函数
~Book();
double getPrice(){return price;}
char * getName(){return bkName;}
static int getNumber(){ return number;}
static double getTotalPrice(){ return totalPrice;}
void display();
};
Book::Book(char *name,double Price) { //构造函数,可以访问静态和非静态成员
strcpy(bkName,name);
price=Price;
number++;
totalPrice+=price;
}
Book::~Book(){
number--; //析构一本书就减少书的本数
totalPrice -= price; //析构一本书就减少书的总价
}
/*此函数仅是一个验证,表示非静态成员函数可以访问静态的数据和函数成员*/
void Book::display(){
cout<<"书名:"<<bkName<<",\t"<<"价格: "<<price<<endl;
cout<<"总数:"<<number<<",\t"<<"总价: "<<totalPrice<<endl;
cout<<"CALL static function: "<<getNumber()<<endl;
}
int Book::number=0; //定义并初始化静态数据成员
double Book::totalPrice=0;
void main(){
Book b1("C++ 程序设计", 32.5);
Book b2("数据库系统原理", 23);
cout<<b1.getName()<<"\t"<<b1.getPrice()<<endl; //L1
cout<<b2.getName()<<"\t"<<b2.getPrice()<<endl; //L2
cout<<"总共: " <<b1.getNumber() <<" 本书,"<<"\t总价: " <<b1.getTotalPrice() <<" 元"<<endl;//L3
{//块作用域
Book b3("数据库系统原理",23);
cout<<"总共: " <<b1.getNumber()<<" 本书,"<<"\t总价: "<<b1.getTotalPrice()<<" 元"<<endl; //L4
}//b3生存期结束
cout<<"总共: " <<Book::getNumber() <<" 本书,"<<"\t总价: "<<Book::getTotalPrice()<<" 元"<<endl;
b2.display();
}
① 同普通成员函数一样,静态成员函数也可以在类内或类外定义,还可以定义成内联函数;
② 在类外定义静态成员函数时,不能加上static限定词。
③ 静态函数只能访问静态成员(包括静态的数据成员和成员函数),不能访问非静态成员。
④ 静态成员函数可以在定义类的任何对象之前被调用,非静态成员只有在实例化对象之后通过对象才能访问。