第二章-类和对象
1.语法形式
定义一个 class 的语法形式如下:
class 类名称
{
public:
外部成员&方法
protected:
保护型成员&方法
private:
私有成员&方法
};
示例:
class A
{
public:
int a,b;
void print1(){ //方法在类内部实现
printf("h1");
}
protected:
int c,d;
void print2(){
printf("h2");
}
private:
int e,f;
void print3(){
printf("h3");
}
};
如果 class 的方法要在外部实现时,使用类名和域运算符( :: )声明
class stu{
public:
void print();
};
void stu::print()
{
cout<<"This is stu"<<endl;
}
2.访问控制
public、protected、private 三个关键字提供了不同的访问控制机制
公有类型成员定义了类的外部接口,在类外只能访问类的公有成员
私有类型成员只能被本类的成员函数访问,来自类外部的访问都是非法的
保护类型成员性质与私有成员性质相似,差别在于保护继承时子类成员函数可以访问父类保护成员
设计一个类,是为了用它,要能够使用,就一定要设计必要的外部接口。
3.对象
在C++中,类的对象就是该类的某一特定实体,声明一个对象和声明一个一般变量相同。
访问对象的成员,采用“.”操作符,一般形式为:
对象名.数据成员名 对象名.函数成员名(参数表)
示例如下:
class B
{
public:
int b;
void print(){
printf("b=%d\n",b);
}
};
int main()
{
B btp;
btp.b=10;
btp.print(); //输出b=10
return 0;
}
C++还可以使用 new 关键字来创建对象。不同的是,使用 new 时需要用对象指针说明引用,对象指针要用“->”操作符来访问对象成员。
class B
{
public:
int b;
void print(){
printf("b=%d\n",b);
}
};
int main()
{
B* btp = new B();
btp->b=10;
btp->print(); //输出b=10
return 0;
}
4.构造函数
构造函数的作用是在对象被创建时利用特定的值构造对象,将对象初始化为一个特定的状态
- 构造函数的函数名与类名相同,而且没有返回值
- 构造函数也是类的一个成员函数,声明为公有函数,但不能在外部显式调用
- 构造函数允许重载,系统会根据初始化定义自动选取构造函数!
- 如果类中没有写构造函数,编译器会自动生成一个隐含的默认构造函数,其参数列表和函数体为空
class A{
public:
A(){} //无参构造函数
A(int i){ //有参构造函数
x=i;
}
A(int i,int j){ //重载
x=i;
y=j;
}
private:
int x,y;
};
int main(){
A a; //调用无参构造函数
A b(2); //调用有参构造函数
A c(3,4);
}
5.复制构造函数
复制构造函数的作用是使用一个已经存在的对象,去初始化一个同类的一个新对象
- 复制构造函数是一种特殊的构造函数,形参是本类对象的引用
- 如果不显式说明,系统会生成一个隐含的复制构造函数,对初始化对象进行拷贝
一般方法为:
class 类名{
public:
类名(类名 & 对象名)
}
class A{
public:
A(int i){ //构造函数
x=i;
}
A(A &p); //复制构造函数
private:
int x;
};
A::A(A &p){ //复制构造函数的实现
x=p.x;
cout<<"复制构造函数被调用"<<endl;
}
int main(){
A a(2);
A b(a); //用对象a初始化对象b,复制构造函数被调用
}
6.析构函数
析构函数是在对象的生存周期即将结束的时候自动调用的,用来完成对象被删除的一些清理工作
- 析构函数也是类的一个公有函数成员,名称是由由类名前面加 ~ 构成,没有返回值
- 析构函数可以在外部显式调用,但不能进行重载
- 析构函数不接受任何参数(但可以是虚函数)
- 如果不显式说明,系统会生成一个函数体为空的隐含的析构函数
class A{
~A(){} //析构函数
};
class A{
~A(){
cout<<"A destroy()"<<endl;
}
};
int main(){
A a;
a.~A(); //显式调用
return 0;
}
7.类的组合
类的组合就是一个类内嵌其他类的对象作为成员的情况,它们的关系是包含与被包含的关系
- 创建类的对象时,如果这个类具有内嵌对象成员,那么各个内嵌对象将首先被自动创建
- 创建对象时既要对本类的数据成员进行初始化,又要对内嵌对象成员进行初始化
- 构造函数的调用顺序为
- (1)调用内嵌函数的构造函数,调用顺序按照内嵌对象在组合类的定义中出现的次序。
- (2)执行本类构造函数的函数体
- 析构函数的调用顺序与构造函数刚好相反
- 如果没显示声明,必要时编译系统会自动生成组合类的复制构造函数
class A{
public:
int x,y;
};
class B{
public:
B(A ab1,A ab2); //组合类构造函数
private:
A a1,a2; //A类对象a1,a2
double sum;
};
B::B(A ab1,A ab2):a1(ab1),a2(ab2){
sum=a1.x+a2.y;
}
Tips
- 前向引用说明
- 前向引用声明,在引用未定义的类前,将该类的名字告诉编译器,让编译器知道这是一个类名
- 使用前向引用声明时,只能使用类的名称,不能涉及任何细节
- 尽管使用了前向引用声明,但是在提供一个类的完整声明前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象
class B; //前向引用说明
class A{
public:
B &b; //可以声明 B类的对象引用或指针
B* c;
B d; //错误,类 B的声明尚不完善
};
class B{
public:
A a; //A已经在B之前声明了
};
- 联合体
- 联合体是一种特殊的类,默认访问控制属性是公有类型的
- 联合体的成员共用相同的内存单元,联合体变量中的成员至多有一个是有意义的
- 联合体不能被继承,不支持包含多态
union Mark{
char grade;
bool pass;
int percent;
};
|