c++学习笔记--类

c++学习笔记--类


refer:

c++ primer

http://blog.sina.com.cn/s/blog_7dc276cd0100tz61.html


在c++中,用类来定义自己的抽象数据结构。


在一个源文件中,一个类只能被定义一次(声明可以多次),如果在多个文件中定义一个类,那么每个文件定义必须完全相同。

可以声明一个类而不定义它。这个声明被称为向前声明,是一个不完全类型(已知其为一个类型,但不知道包含哪些成员)。

在创建类的对象之前必须完整地定义这个类(编译器需要知道这个类对象的大小以为其分配相应的内存)。同样,在使用指针、引用访问类的成员前,必须定义类。


由于类定义之后可以接一个对象列表,因此定义必须以分号结束。


const类对象只能调用const成员函数;非const类对象可以调用const与非const成员函数。


当成员函数需要返回对象本身时,需要使用this指针,例:

class test;

test& test::func()

{

return *this;//注意,这时*this,不是this

}

test test_obj;

test_obj.func().func().func();

这时可以使用test类对象,将调用成员函数连接成一个单独的表达式。

类数据成员与类成员函数中的局部变量冲突且需要使用类数据成员时,使用this指针。


mutable关键字:

const类对象只能访问const类成员函数,const类对象及const类成员函数原意就是不允许修改类的任何数据成员,但是如果需要修改其中一部分数据成员,而不允许修改其他的数据成员,那么可以再想修改的数据成员前加上关键字mutable,这样就医修改const类对象的mutable数据成员,在const成员函数中也可以修改mutable数据成员。


类作用域:

在类的作用域之外,只能通过类对象、类对象指针来访问类的成员。

而定义类型的成员,使用作用域操作符::来访问,例:

class test{

int num;

typedef double size;

};

int main()

{

test::size  size_t = 0.0;//只能使用::来访问size

return 0;

}


形参表和函数体位于类作用域中;

函数定义在类定义体之外时,函数的返回值类型不在类作用域之内,如果函数返回值类型是在类内定义的数据类型,那么必须显示使用::,例:

int size = 99;

class test{

typedef int size;

size func();

};

test::size test::func()

{

return  ::size;//size是全局变量值为99,显式使用::会跳出类作用域

}

size是在类内定义的数据类型,因此必须显示使用test::,如果不加,那么编译器是不认识size的。


类作用域中的名字查找:

1.在使用改名字的块中查找名字的声明;

2.如果找不到,那么在保卫的作用域中查找;

3.还找不到,编译器报错。


编译器编译类定义时,是分两步完成的:

1.编译后成员声明;

2.编译完所有成员声明后,才编译成员的定义。


构造函数:

class test()

{

test():num(0){} //这是初始化

test(){num = 0;} //这是赋值

int num;

double rate;

};

test::

构造函数不能是const,也是没必要的,因为可以使用非const构造函数生成const类对象,以此来初始化const对象。//TODO 这种转化有没有产生一个临时变量,是不是属于自动转化?

普通内置类型的数据成员不进行隐式初始化,所以对这些成员进行初始化还是赋值在性能上等价的。

内置类型数据成员如果定义在全局作用域,那么会进行初始化。

类类型的数据成员会进行隐式初始化,使用该类类型的默认构造函数。

但是对于任何const或引用数据成员及没有默认构造函数的类类型数据成员必须使用初始化。因为const及引用无法赋值只能初始化。

数据成员的初始化顺序是其声明的次序。


类如果定义了一个构造函数,那么编译器则不会生成默认构造函数。默认构造函数是没有形参的构造函数。

在一个类中如果定义了一个具有全部是默认实参的构造函数,那么就不能再定义重载构造函数,因为在会发生重载的歧义。


一个类A没有默认构造函数(或者具有默认实参的构造函数)意味着:

1.每个该类对象初始化必须传入实参;

2.具有该类A对象作为数据成员的类B,如果B想要提供默认构造函数,那么B必须在默认构造函数中显示地初始化A对象;

3.A类对象不能作为动态分配数组的元素类型,例:int num = 10; A array[num];语句非法

4.A类的静态数组必须为每个元素提供一个显示初始化,例: A array[10];语句非法

5.保存A类对象的容器不能使用接受容器大小而不提供元素初始化的构造函数,例:std::vector<A> vec_A(100);这个语句是非法的。


隐式类型转换:

具有一个形参的构造函数定义了从形参类型到该类类型的隐式转换,例:

class test()

{

test(int);

void func(test);

}

test tst(10);

tst.func(99);//在test类中func函数需要一个test类型对象,但是现在传入一个int对象,编译仍然可以过,这是因为编译器使用构造函数将int转换为test。

可以使用关键字explicit来抑制此种隐式转换。explicit关键字只能用于类内部的构造函数声明上,类外部定义不能重复它。当构造函数被声明为explicit时,编译器将不是呀他作为转换操作符(TODOy我理解是不将此构造函数作用于类内部默认的操作符重载oprator=)。

可以显式地使用构造函数来生成转换,例:

class test()

{

test(int);

void func(test);

}

test tst(10);

tst.func(test(99));//

显式使用构造函数只是中止了隐式地使用构造函数,任何构造函数都可以用来显式创建临时对象。



友元:

友元机制允许一个类将对其非公有成员的访问权授予指定的函数或类。友元声明只能在类定义的内部以关键字friend开始。友元声明可以出现在类的任何地方。

类必须将重载函数集中每一个希望设为友元的函数都声明为友元。


无法定义const类型的引用,引用无法被赋值只能初始化,引用是对象指向内存的别名但是无法解地址*。


static类成员的优点:

1.static成员名字在类的作用域内,因此避免了与其他类的成员或全局对象名字冲突;

2.可以实施封装,static类成员可以使私有成员,而全局对象不可以;

3.代码清晰,容易看出static成员是与特定类关联的。


static类数据成员是保存在bss中而不是在类对象内。static类数据成员只能在类定义外部定义,且定义时不能添加static关键字,不能通过类构造函数初始化,而是在定时时初始化。如果初始化式是一个常量表达式,那么const static数据成员可以:1在类内部初声明且始化,内外部定义且不能初始化;2在内部声明且不初始化,类外部必须定义初始化;3在类内部声明且定义它。例:

class test()

{

static int num;//不能在此处初始化

static const int rate0 = 99;//因为99是是常量表达式,且在类内部声明初始化

static const int rate1 = 99;//因为99是是常量表达式,且在类内部声明初始化

static const int rate2 = 99;//因为99是是常量表达式,且在类内部声明定义初始化,类外部没有定义

private:

int func();

}

int test::num = func();//只能在内定义外部处定义且不能标识为static,且static成员在类作用域内,因此可以访问该类的私有成员

const int test::rate0;//不能初始化

const int test::rate1 = 99;//必须初始化

要记得定义一个变量时不一定需要初始化。

变量的定义(definition):用于为变量分配存储空间,还可以为变量指定初始值(也可以不初始化)。在一个程序中,变量有且仅有一个定义。

变量的声明(declaration):用于向程序表明变量的类型和名字。

定义也是声明:当定义变量时我们声明了它的类型和名字。可以通过使用extern关键字声明变量名而不定义它。

对于int a;来说,它既是定义又是声明;对于extern int a;来说,它是声明不是定义。一般为了叙述方便,把建立存储空间的声明称定义,而不把建立存储空间的声明称为声明。


static成员函数没有this指针。static成员函数除了可以通过类对象、对象指针、对象引用来调用外,还可以使用【类名::方法】来调用。static成员函数不能被声明为const类型、virtual类型。











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值