C++基础-类与对象
来源:互联网 发布:selected知乎 编辑:程序博客网 时间:2024/06/07 22:40
认识类和对象
- 面向对象四大特征
抽象:抽出事物 的最本质的特征;
封装:把数据和处理(函数)包在一起;
继承:数据和处理函数的传承;
多态:同一个事物(函数)的多种形态;
类的定义和创建
类的定义:与C++中的’struct‘类似
class 类 名{ 成员变量; 成员函数;};
构成
数据成员(data member)/成员变量/属性:对象内部数据和状态,只能在类定义中声明,可以在成员函数中直接调用。
成员函数/方法:对象相关的操作,可以在类内实现或类外实现。作用域运算符:’::’ 表示函数归属。
访问限制符
private(默认|私有)
public(公开)
protected(保护)实践中,成员变量多数情况使用’private’或’protected’,成员函数多数情况使用’public’。通常使用成员函数改变对象的成员变量。
声明与实现分离
- 头文件 - - 声明
方式:#pragma once或#ifdef ….#endif
作用:防止头文件二次编译 源文件 - -实现
引用头文件:#include <>(标准库函数)/#include “”(自定义/第三方函数)‘class’与’struct’的区别
1.默认的访问控制不同
‘struct’是’public’
‘class’是’private’
2.’struct ‘可以使用花括号内的初始值列表’{…}’初始化,’class’不可以(c++98不可以,C++11可以)。注意:
C++中的’struct’可以有成员函数,而C不可以。
C++中的’struct’可以使用访问控制关键字(’private’,’public’,’protected’)。- 成员变量默认初始化为随机值(主要影响指针)。
对象创建
- 直接定义 - - 类作为类型定义变量 - - 栈上创建
类名 对象1;// 调用默认构造函数类名 对象2 = 对象1;// 调用复制构造函数类名 对象3(对象1);// 调用复制构造函数
- 动态创建 - -堆上创建
类名* 对象指针 = new 类名;// 调用默认构造函数delete 对象指针;
int *p = new int[10];delete p;//只释放p[0]delete [] p;//释放全部数组
基本类型的初始化新增语法:
int a(0);//等价于int a = 0;const float b(1.0);//等价于cosnt float b = 1.0;
空结构体与空类的大小(‘sizeof’)为 ‘1’,主要在于初始化/实例化时,编译器给变量/对象分配内存(地址),通常,‘sizeof(类型)==’sizeof(变量)’。
注意:C++除了特殊情况,很少直接使用malloc/free()申请释放内存,取而代之的是’new/delete’。
’this‘ 指针
作用域 - - 类内部
特点
1.类的一个自动生成、自动隐藏的私有成员
2.每个对象仅有一个’this’指针
3.当一个对象被创建时,‘this’指针就存放指向对象数据的首地址
4.不是对象本身的一部分,不会影响sizeof(对象)结果如果成员函数形参与成员变量同名,使用‘this->’作为前缀区分。
方法
构造函数
- 语法
类名(参数){ 函数体}
- 在对象被创建时自动执行
- 构造函数的函数名与类名相同
没有返回值类型、也没有返回值
调用时机
- 对象直接定义创建 - -构造函数不能被显式调用
- ‘new’动态创建
- 默认构造函数
类中没有显示的定义任何构造函数,编译器就会自动为该类型生成默认构造函数 - 构造函数的三个作用
- 给创建的对象建立一个标示符
- 为对象数据成员开辟内存空间
- 完成对象数据成员的初始化
- 语法
类名(参数):成员变量(参数){ 函数体}
- 作用:初始化非静态成员变量
- 说明:从概念上来讲,构造函数的执行可以分为两个阶段,初始化阶段和计算阶段,初始化阶段先于计算阶段
- 必须使用初始化列表的情况
- 常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面。
- 引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面。
- 没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。
- 初始化列表与构造函数内部成员变量赋值的区别:成员变量初始化与成员变量赋值
能使用初始化列表的时候尽量使用初始化列表
- 成员变量的初始化顺序:成员变量在使用初始化列表时,与构造函数中初始化成员列表的顺序无关,只与定义的成员变量的顺序有关。
C++的函数可以加默认参数。
写法:
- 默认参数必须写在函数声明中,不能写在函数实现的参数列表中
- 默认参数必须写在所有非默认参数的后面
- 默认参数可以写任意多个
使用:
默认参数可以不用传递值,此时,使用默认值
默认参数可以传值,此时,使用实参值
析构函数
- 语法
~类名{ 函数体}
- 析构函数的函数名与类名相同
- 函数名前必须有一个’~’
- 没有参数
- 没有返回值类型、也没有返回值
只能有一个析构函数
调用时机
- 对象离开作用域
- ‘delete’
- 默认析构函数:类中没有显式的定义析构函数,编译器就会自动为该类型生成默认析构函数
- 作用:释放对象所申请占有的资源
引用(别名)
- 语法
声明:‘const类型名& 对象名’/‘类型名& 对象名’
使用:与对象变量、基本类型变量一样 - 何处使用引用
- 函数参数列表
- 成员变量 - - 对象初始化时,必须显示初始化的变量
- 为何使用引用
- 避免对象复制
- 避免传递空指针
- 使用方便
类型: 基本类型(‘bool’、‘char’、‘int’、‘short’、‘float’)
复合类型(指针、数组、引用)
自定义类型(‘struct’、‘union’、‘class’)引用作用:取代指针
引用常用于两种情形:成员变量和函数的参数列表。引用与指针的区别:
1. 指针指向一块内存,它的内容是指内存的地址;引用是某块内存的别名;
2. 引用只能定义时被初始化一次,之后不可变;指针可以改变;
3. 引用不能为空,指针可以为空;
4. 引用使用时无需解引用‘*’,指针需要解引用;
5. ‘sizeof(引用)’的得到的是所指向的变量/对象的大小,而‘sizeof(指针)’得到的是指针本身的大小。
拷贝/复制构造函数
- 语法:
类名(类名& 形参){ 函数体}
或者
类名(const 类名&形参){ 函数体}
或者
类名(const 类名 形参){ 函数体std:swap();}
- 调用时机
- 一个对象作为函数参数,以值传递的方式传入函数体
- 一个对象作为函数返回值,以值从函数返回
- 一个对象用作给另外一个对象进行初始化(赋值初始化)
实践说明:
gcc自动NRV(named return value)优化,不执行拷贝构造函数,需要在编译命令添加选项禁止‘-fno-elide-constructors’;
vs会执行拷贝构造函数
总之,尽量不要返回局部对象。
默认拷贝构造函数
- 本质:内存拷贝
- 作用:复制一个已经存在的对象
如何禁用默认拷贝构造函数?在类定义,添加私有的复制构造函数的声明,但不实现。
赋值运算符重载函数
- 语法
类名& operator = (const 类名& 形参){ //赋值操作 return *this;}
- 调用时机:赋值
- 默认赋值运算符重载函数:内存拷贝
作用:赋值
如何禁用默认赋值运算符重载函数?在类定义,添加私有的赋值运算符重载函数的声明,但不实现
拷贝构造函数与赋值运算符的区别
拷贝构造函数:当一个已经存在的对象来初始化一个未曾存在的对象
赋值操作符:当两个对象都已经存在时
深拷贝与浅拷贝
- 浅拷贝:只拷贝指针地址
- 深拷贝:重新分配堆内存,拷贝指针指向内容
友元
- 作用:非成员函数访问类中的私有成员
- 分类
- 全局友元函数:将全局函数声明成友元函数
- 友元成员函数:类的提前引用声明,将一个函数声明为多个类的友元函数
- 友元类:将整个声明为友元
- 特点
- 友元关系单向性
- 友元关系不可传递
‘const’限定符
- 本质:不可修改
- ‘const’与变量/对象
const 类型 变量 = 初始值const 类型 对象
- 定义时必须初始化
- 全局作用域声明的’const’变量默认作用域是定义所在文件
- ‘const’对象只能调用’const’成员
’const’与宏定义’#define’的区别
* ‘const’与指针
No.2是使用最频繁的方式
- ‘const’与引用
‘类型 const & 变量 = 初始值;’与’const 类型& 变量 = 初始值;’都是引用对象不能改变 - ‘const’与函数的参数和返回值
const 成员变量
- 不能在类声明中初始化’const’数据成员
- ‘const’成员变量只能在类构造函数的初始化列表中初始化
如果使用’const’成员变量不能使用赋值运算符重载函数
声明
class 类名{public: 返回值类型 函数名(形参列表) const;};
- 定义
返回值类型 函数名(形参列表) const;
必须在成员函数的声明和定义后都加上’const’
只要能够使用’const’,尽量使用’const’。
‘static’限定符
本质
1. 生存周期:整个程序的生存周期;
2. 作用域:属于类,不属于对象.
- 声明
class 类名{ static 返回类型 函数(形参列表);};
- 定义
返回类型 类名::函数(形参列表){ 函数体;}
- 调用
类名::函数(实参列表);
- 规则
- ‘static’只能用于类的声明中,定义不能标示为‘static’
- 非静态是可以访问静态的方法和函数
- 静态成员函数可以设置‘private’、‘public’、‘protected’访问权限
- 禁忌
- 静态成员函数不能访问非静态函数或者变量
- 静态成员函数不能使用‘this’关键字
- 静态成员函数不能使用cv限定符(’const‘与’virtual‘)
因为静态成员函数是属于类而不是某个对象,静态成员变量所有类的对象/实例共享
单例模式:使用静态成员变量和静态成员函数。
‘const static’限定符
注意:‘static const’/‘const static’成员变量必须是整形。
函数的调用优化
‘inline’ - - 宏定义的接班人。- 条件:一般用在代码比较简单的函数
- 语法
- 关键字‘inline’必须与函数实现/定义体放在一起才能使函数成为内联
- 定义在类声明之中的成员函数将自动地成为内联函数
- 慎用内联
- 如果函数体内的代码比较长,使用内联将导致内存消耗代价较高
- 如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大
- 不要随便地将构造函数和析构函数的定义放在类声明中
本质:内联函数的代码直接替换函数调用,省去函数调用的开销
运算符重载
- 语法:运算符重载主要有两种方式实现:
- 成员函数运算符重载
返回值类型 operator 运算符(参数){
函数体
} - 友元函数运算符重载
- 成员函数运算符重载
friend 返回值类型 operator 运算符(形参列表){ 函数体}
- 分类
bool operator 运算符 (const 类名&,const 类名&)
4 单目逻辑运算符 !
bool operator !() const
bool operator ! (const 类名&)
5 单目算术运算符 +
-
类名& operator 运算符 ()
类名& operator 运算符 (const 类名&)
6 双目位运算符 &
¦
类名 operator 运算符 (const 类名& ) const
类名 operator 运算符 (const 类名& ,const 类名& )
7 单目位运算符 ~
类名 operator ~ ()
类名 operator ~ (类名&)
8 位移运算符 <<
>>
类名 operator 运算符 (int i) const
类名 operator 运算符 (const 类名&,int i)
9 前缀自增减运算符 ++
--
类名& operator 操作符 ()
类名& operator 操作符 (类名&)
10 后缀自增减运算符 ++
--
类名 operator ++ (int)
类名 operator ++ (类名&,int)
11 复合赋值运算符 +=
-=
*=
/=
%=
&=
¦=
^=
类名& operator 运算符 (const 类名& )
类名& operator += (类名&,const 类名&)
12 内存运算符 new
delete
参见说明 参见说明 13 流运算符 >>
<<
- 参见说明 14 类型转换符 数据类型
参见说明 - 15 其他运算符重载 =
[]
()
->
参见说明 -说明:内存运算符比较复杂;
说明
- 内存运算符比较复杂:
成员函数
- 内存运算符比较复杂:
void *operator new(size_t size);void *operator new[](size_t size);void operator delete(void*p);void operator delete [](void* p);
友元函数
void *operator new(类名,size_t size);void *operator new[](类名&,size_t size);void operator delete(类名&,void*p);void operator delete [](类名&,void* p);
- 流运算符
流运算符只能使用友元函数实现。
inline ostream &operator << (ostream&, 类名&)inline istream &operator >> (istream&, 类名&)
- 类型转换符
这些运算符只能使用成员函数实现。
operator char* () const;operator int ();operator const char () const;operator short int () const;operator long long () const;
- 其他运算符重载
这些运算符只能使用成员函数实现。
类名& operator = (const 类名& );char operator [] (int i);//返回值不能作为左值const char* operator () ();T operator -> ();
规则
- 五个不能重载的运算符:成员运算符
.
、指针运算符*
、作用域运算符::
、sizeof
、条件运算符?:
- 不允许用户自定义新的运算符,只能对已有的运算符进行重载
- 重载运算符不允许改变运算符原操作数的个数
- 重载运算符不能改变运算符的优先级
- 重载运算符函数不能有默认的参数,会导致参数个数不匹配
- 五个不能重载的运算符:成员运算符
本质
函数重载
- 【C++】类与对象基础
- Object-C基础(7)——类与对象
- 对象与类基础
- C++-类与对象
- C++:类与对象
- C++(类与对象)
- 【c++】类与对象
- C++-类与对象
- PHP基础 类与对象
- c#基础-类与对象
- C++类与对象基础
- JAVA基础.类与对象
- C++基础-类与对象
- 类与对象的基础
- 面向对象基础--类与对象
- java基础-面向对象-类与对象
- 黑马程序员---OC基础---OC简介、OC与C的差异、类和对象与方法
- C#(面向对象基础-抽象类与接口)下-1
- 黑马商城项目(三)之一
- 伪类
- 3838. 【NOIP2014模拟9.14】Super Big Stupid Cross
- 从控制台输入字符 统计该字符"e"所出现的个数
- COCI 2010/2011 6th round--ABECEDA【拓扑排序】【字符串处理】
- C++基础-类与对象
- as3实现XML中特殊字符的转义还原
- UART寄存器详解
- 第一篇博客
- Tomcat启动时卡在“INFO: Deploying web application directory ......”的解决方法
- 合并两个排序的链表使之依然有序(不开辟新空间在原链表上操作的非递归版本)
- 数据结构——单链表(C语言实现)
- css实现垂直居中的常用技巧
- tf.nn