类的定义和声明
每个类可以没有成员,也可以定义多个成员,成员可以是数据,函数,或类型别名。
成员函数在内部定义的函数默认是inline。
当我们定义一个类对象时,每个对象具有自己的类数据成员的副本,修改它的数据成员不会改变其他对象的数据成员。
this指针
尽管在员函数内部显式引用this通常是不必要的,但有一种情况必须这么做:当需要将
一个对象作为整体引用而不是引用对象的一个成员时,使用this,该函数返回对调用该函数的对象的引用。
可变数据成员
mutable
const用法
一般常量
const int x=9;
int const x=9;
int const a[5]={1,2,3,4,5]
常对象
<类名> const <对象名>
const <类名> <对象名>
定义常对象时,同样要进行初始化,并且该对象不能被更新。
常指针
定义一个指向字符串的指针常量和定义一个指向字符串常量的指针,const位置不同,
char* const ptr=stringptr;stringptr能更新,ptr所指字符串不能更新。
const *ptr=stringptr;ptr所指字符串不能更新,即stringptr不能更新。
常引用
const <类型说明符> &<引用名>
const double & v1;
常成员函数
<类型说明符> <函数名> (<参数表>) const;
只有常成员函数才能操作常量或常对象,没有使用const说明的成员函数不能用来操作常对象。
类中const数据成员时,只能通过成员初始化列表的方式初始化。
const是加在函数说明后面的类型修饰符,它是函数的一个组成部分,因此,在函数实现部分也要带const。
#include
class R
{
public:
R(int r1, int r2) { R1=r1; R2=r2; }
void print();
void print() const;
private:
int R1, R2;
};

void R::print()
{
cout<<R1<<endl<<R2<<endl;
}

void R::print() const
{
cout<<R1<<endl<<R2<<endl;
}

void main()
{
R a(5, 4);
a.print();
const R b(20, 52);
b.print();
}
static const int b;静态数据成员
const int A::b=10;
const几点用法
1.限定符声明变量只能被读
2.必须初始化
3.可以通过函数对常量进行初始化
4.const的常量值是可以修改的
volatile const int i=0;
int *p=(int*) &i;
*p=100;
const修饰的类数据成员
class A
{
const int size;
}
const数据成员只是在某个对象生存期内是常量,而对于整个类而言确是可变的。不同对象其const数据成员可以不同。所以不能在类声明中初始化const数据成员。
如果想建立在整个类中都恒定的常量,可以用枚举变量实现。
class A
{
enum { size1=100,size2=90};
}
枚举变量不会占用对象的存储空间。
const修饰指针
int b=400;
const int* a=&b;
int const *a=&b;
int* const a=&b;
const int* const a=&b;
const位于*左侧,const修饰指针指向的变量,即指针指向为常量。
const初始化
1非指针const常量初始化
A b;
const A a=b;
2.指针const常量初始化
A* d=new A();
const A* c=d;
或const A* c=new A();
3.引用const常量初始化
A f;
const A& e=f;
const在函数声明中的应用。
1.修饰参数的const。void fun0(const A* a);void fun1(const A& a);
用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为const A* a,则不能对传递进来的指针的内容进行改变,保护了原指针所指向的内容;如形参为const A& a,则不能对传递进来的引用对象进行改变,保护了原对象的属性。
[注意]:参数const通常用于参数为指针或引用的情况,且只能修饰输入参数;若输入参数采用“值传递”方式,由于函数将自动产生临时变量用于复制该参数,该参数本就不需要保护,所以不用const修饰。
[总结]对于非内部数据类型的输入参数,因该将“值传递”的方式改为“const引用传递”,目的是为了提高效率。例如,将void Func(A a)改为void Func(const A &a)
对于内部数据类型的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void Func(int x)不应该改为void Func(const int &x)
修饰返回值的const,如const A fun2( ); const A* fun3( );
这样声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。const Rational operator*(const Rational& lhs, const Rational& rhs)
{
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}

返回值用const修饰可以防止允许这样的操作发生:Rational a,b;
Radional c;
(a*b) = c;

一般用const修饰返回值为对象本身(非引用和指针)的情况多用于二目操作符重载函数并产生新对象的时候。
[总结]
1. 一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下:如果返回值为某个对象为const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例) ,则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。
2. 如果给采用“指针传递”方式的函数返回值加const修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。如:
const char * GetString(void);
如下语句将出现编译错误:
char *str=GetString();
正确的用法是:
const char *str=GetString();
使用类的成员
在类作用域外,成员只能通过对象或指针分别使用成员访问操作符.或->访问。
一些成员使用成员访问操作符,另一些直接通过类使用作用域操作符(::)访问。一般的数据或函数成员必须通过对象来访问。
函数返回类型不一定在类作用域中
与形参类型相比,返回类型出现在成员名字前面。如果函数在类定义体外定义则用于返回类型的名字在类作用域外。如果返回类型使用由类定义的类型,则必须使用完全限定名。
class Screen
{
public:
typedef string::size_type index;
index get_cursor() const;
}
inline Screen::index Screen::get_cursor() const
{
}
类的成员函数的形参与类的数据成员名称最好不一样。
初始化的次序通常无关紧要。如果一个成员是根据其他成员而初始化,则次序很重要。
友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类。
static类成员
每个类数据成员独立于该类的任意对象而存在,每个static数据成员是与类关联的对象,并不与该类的对象关联。
类也可以定义static成员函数。static没有this形参,它可以直接访问static成员,但不能使用非static成员。


复制构造函数具有单个形参,该形参(通常用const修饰)是对该类对象的引用。但定义一个新对象并用一个同类型的对象对他进行初始化是,将显式调用复制构造函数。当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式调用复制构造函数。
复制构造函数可用于:
.根据另一个同类型的对象显式或隐式初始化一个对象
.复制一个对象,将它作为实参传给一个函数
.从函数返回时复制一个对象
.初始化顺序容器中的元素。
.根据元素初始化式列表初始化数组元素原对象的副本。
C++支持两种初始化形式:直接初始化和复制初始化。复制初始化用=符号,而直接初始化将初始式放在圆括号中。
对于类类型对象时,两种初始化有所不同:直接初始化直接调用与实参匹配的构造函数,复制初始化总是调用复制构造函数。复制初始化首先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象。
合成的复制构造函数
如果我们没有定义复制构造函数,编译器会为我们合成一个。与合成的默认构造函数不同,即使我们定义了其他构造函数,也会合成复制构造函数。合成复制构造函数的行为是,执行逐个成员初始化。将新对象初始化。
所谓逐个,指的是将现有对象的每个非static成员,依次复制到正创建的对象。
复制构造函数就是接受单个类类型引用形参(常用const修饰)的构造函数。
只包含类类型成员或内置类型(但不是指针)成员的类,无须显式的定义复制构造函数,也可以复制。
禁止复制
有些类需要完全禁止复制,类必须显式声明其复制构造函数为private。
赋值操作符的返回类型应该与内置类型赋值运算返回的类型相同。内置类型的赋值运算返回对右操作数的引用。因此,赋值操作符也返回对同一类类型的引用。
class A
{
public:
A& operator=(const A&)
};

合成赋值操作符
合成赋值操作符与合成赋值构造函数的操作类似。它会执行逐个成员赋值:
A::operator=(const A &a)
{
isbn=a.isbn;
revenue=a.revenue;
return *this
}
合成赋值操作符根据成员类型使用合适的内置或类定义的赋值操作符,依次给每个成员赋值,改操作符返回*this,它是对左操作数对象的引用。
析构函数
1.何时调用析构函数
撤销类对象时会自动调用析构函数
A *P=new A;
{
A(*P);
delete p;
}
动态分配的对象只有在指向该对象的指针被删除时才撤销。如果没有删除指向动态对象的指针,则不会运行该对象的析构函数,对象就一直存在,从而导致内存泄露,而且,对象内部使用的任何资源也不会释放。
如果类需要析构函数,则它也需要赋值操作符和复制构造函数,这是三法则。指的是如果需要析构函数,则需要所有这三个复制控制成员。
管理指针成员

 

 

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值