c++关于类的基础学习
类 :在c++中大体分为两种,一 内置类型,如int double用户等 二 用户自定义类UDT
问:为什么要使用用户自定义类?
答:编译器不可能知道我们想使用的全部类型。但是标准库类型已经给我们提供了一些非常有用的类,比如vector,string,ostream等等,但是远不能满足需求。尤其是在面向对象的程序设计中,我们需要用自定义的一个类型独立的去表示这个对象的一些特性,所以在面向对象的程序中我们看到更多的是一个一个的对象,而在c程序中我们看到更多的是函数和表达式。类又是描述一个对象的关键和基础。
1. 类的表达形式:
class X{
public:
int m;
int mf(int v){int odd = m;m = v;return odd}
};
用来定义类的组成部分,它们叫成员。读取成员规则如下:
X var;
var.m = 7;
var.mf(9);
2.接口和实现
class X{
public:
//这个是接口的标识,它是公共的
private:
//这个是实现标识,它是私有的
}
成员默认是私有的,即如果不加标识,就等同于私有
http://soft.chinabyte.com/database/340/12457340.shtml 经典 什么是不变式
c++提供了一种可用来描述没有私有实现的细节的类,就是 结构体
struct X{
int m;
} ; 等价于
class X{
public:
int m;
};
2.成员函数和构造函数
struct Date{ struct Date{
int y; int y,m,d;
int m; Date(int y,int m,int d);//与类同名的成员是特殊成员,叫构造函数,
专门用于初始化。类型本身具有一个需要参数的构造函数,如果程序员忘了利用,系 统会报错!!!
int d; void add_day(int n);
} ; };
例如:
Date mybirthday;//error:mybirthday not initial
Date today; Date today(12,24,2007);//error 日期不合法
today.y = 2005; Date last(2000,12,31);//right
today.m = 24;//error 非法月份 Date christams = Date(1976,12,24);//ok 麻烦
today.d = -3;//非法日期 我们需要辅助函数来进行初始化检查,数据合法性检查
2.保持细节私有性
上述结构体方式,用户可以任意修改结构体中的数据,比如 Date last(2000,12,31);
last.m = 14;//非法,不合理的月份
为了避免这种大的错误,我们让数据私有,不能让用户随意修改,但是会提供一个公有函数仅供用户访问。
class Date{
private:
int y,m,d;
public:
Date(int y,int m, int d);
void add_day(int n);
int year(){return y};
int month(){return m};
int day(){return d};
};
Date last(2000,12,31);
count<< last.month();<<endl;//ok
判定有效值得规则称为不变式
如果我们不需要对处理的数据,规定不变式,那我们处理的就是普通数据,那就用struct,不用使用类了
struct不能对自身结构中的数据进行保护,所有的数据都是public的,可以随意修改
3.定义成员函数
在类外定义成员函数的语法规则:
Date::Date(int yy, int mm,int dd)
:y(yy),m(mm),d(dd)
{
}类成员初始化的语法
void Date::add_day(int n)
{
}
... ...
我们也可以在类中定义成员函数,但是不建议这么做,过大的成员函数,会影响接口的展现。
如果像 int month(){return m};这样内容比较少的成员函数,放在内部看起来更为直接,我们也可以考虑放在类中
成员函数定义在类的内部两个作用:
1.函数将成为内联的,即内联函数,编译器为此函数调用生成代码时,不会真正的生成函数调用,而是将代码嵌入到调用者代码中。对于month()这种函数,代码少,频繁调用,这种方式会带来性能的提升
2.每当我们对内联函数体做出修改时,所有使用这个类的函数不得不重新编译。如果函数体位于声明之外的话,就不必这样,只在类改变接口的时候才需要重新编译程序。对于大程序老说,函数体改变时无需重新编译程序会是一个极大的优势
总结:除非你明确需要从小函数中获得性能提升,否则不要将成员函数放在类声明中。对于五行以上的函数,不会从内联中获益。对于超过一两个表达式的函数,不建议采用内联函数。
4.引用当前对象
void f(Date d1,Date d2)
{
count<<d1.month<<d2.month<<endl;
}
每个成员函数都有一个隐式参数,用来识别调用它的对象
5.报告错误
发现无效日期我们需要抛出一个异常
class Date{
pubilic:
class Invalid{};
Date(int y,int m,int d);
private:
int y,m,d;
bool check();//哪些函数放在私有实现,哪些放在公共接口,怎么划分
};
Date::Date(int yy,int mm,int dd){
if(!check())throw Invaild();//check返回值是false,这么表示有问题啊
}
bool Date::check()
{ if(m<1||m>12) return false;
};
void f(int x,int y)
try{
Date dxy(2004,x,y);
count<<dxy<<endl;
dxy.add_day(2);
}
catch(Date::Invaild){
error("Invaild date");
}