C过渡到C++(3)
接上一篇博文引用
引用是变量的一个别名.
引用是没有独立空间的, 他和指向的变量共用内存空间, 所以引用必须指向一个变量.引用一旦被确定后, 它是无法被更改到另外变量的.
我们来看一下指针
指针是一种数据类型.
指针拥有数据空间.- 指向某个变量的地址后, 可以在指向另外的一个变量地址.
看个引用的例子#include <iostream>
// 引用例子
void Swap(int &iValA, int &iValB)
{
int iTmp = iValB;
iValB = iValA;
iValA = iTmp;
}
int main()
{
int iVal = 100;
int &refVal = iVal;
std::cout << "iVal:";
std::cout << iVal;
std::cout << "RefVal:";
std::cout << refVal;
int iNum = 50;
refVal = num; // 相当于 iVal = num;
// 此时 是能正常进行交换的
Swap(iVal, iNum);
return 0;
}为了更加好理解, 可以这么想: 引用是一个阉割版的指针
它更加的安全, 拥有类型检查, 拥有长度检查
const小知识
// 猜猜谁不能被修改?
int main()
{
int iVal = 100;
const int* pVal = &iVal; // 值不能修改
int const* pVal = &iVal; // 值不能修改
int* const pVal = &iVal; // 地址不能修改
return 0;
}记住, const是左结合的
常量引用
// 常量引用例子
int main()
{
const int num = 500;
const int& refNum = num;
return 0;
}注意
int main()
{
const int& num = 500;
const int* pNum = #
// 在VS编译器中, 它会在常量区分配空间存储500...
return 0;
}这个操作是无意义的
它属于未定义的行为
它依托于编译器的处理
十分不建议这样的代码
按引用传递
- 引用传值, 传递的是本身.
- 实际上, 编译器同样对变量进行了拷贝(地址).
- 本身实际上是变量的地址.
- 好处: 将参数作为变量使用, 并且作用域是外部的.
// 引用传值
#include <iostream>
void Swap(int &iValA, int &iValB)
{
int iTmp = iValB;
iValB = iValA;
iValA = iTmp;
}
int main()
{
int iVal = 100;
int iNum = 50;
// 引用传值
Swap(iVal, iNum);
return 0;
}函数之间的值传递是通过
栈来完成的.
在参数是引用的话, 传递的实际上是地址
在结构体作为参数的时候,使用引用是比较好的.
但是,风险是可能会修改外部的变量
所以, 基本上会使用常量引用来进行参数传递.
安全, 高效
// 引用传值
#include <iostream>
void Dosomething(const int &iValA, const int &iValB)
{
// ...
}
int main()
{
int iVal = 100;
int iNum = 50;
// 引用传值
Dosomething(iVal, iNum);
// iVal 和 iNum 都不会有变化
return 0;
}引用作为返回值
// 返回引用例子
#include <iostream>
int iArray[] = {0, 1, 3, 5 };
int& Index(int idx)
{
return iArray[idx];
}
int* Index2(int idx)
{
return &iArray[idx];
}
int main()
{
Index(0) = 100;
*Index(1) = 50;
std::cout << iArray[0] << " " << iArray[1];
return 0;
}引用和指针
引用可以代替任何传值类的指针参数. ???引用不能代替指针!.引用无法指向堆区.
引用的冷知识
// 指针的引用
int main()
{
int iNum = 0;
int* p = &iNum;
int *&refp = p;
return 0;
}auto
auto是C11中加入的全新变量类型
它会自动推导所需要的类型.
//永远不要写如下代码
int iNum = 0;
int* p = &iNum;
auto &refP = p;类和对象
类
我们先从广义上来理解一下 类.
比如人类, 人类是一个种类, 拥有一些共同的特征和能力.
共有的一些特征, 我们称之为 "属性"
共同的一些能力, 我们称之为 "方法"
人类, 是一个抽象出来, 具有共性的一个类别, 我们称之为 "类"在C++中, 使用
class关键字来进行类的声明.
类中的属性, 就是一些变量
类中的方法, 就是我们的函数
类是"虚"的, 在我们的C++中, 它是不占用内存的
类的种类
类可以分为
抽象类和工具类.抽象类抽象类就是我们对一些共同的特点(变量)和行为(方法)进行抽象而得到的类.
想要写一个抽象类, 需要知道这个类想要表示的是什么, 需要根据业务来定
工具类工具栏是把我们一些零散或常用或具有某一类特定功能的方法组织到一起产生的类.
典型的代表: string类
类的访问权限
私有 private
类的访问权限默认是
私有的.private
是只有在类内部才能访问的.
公有 public
public
在类的内外部都可以访问.
保护 protected
protected
- 此处仅作了解, 后学到子类时在进行详细了解.
访问权限让我们对类的可控性更强
构造函数和析构函数
构造函数
- 构造函数名
必须和类名相同. - 构造函数
没有返回值, 并且不可加返回值类型. - 在
该类有新对象产生时, 会自动调用类的构造函数. - 当构造函数
私有时, 外部不能够调用,该类不能被新建对象 ① - 如果
不提供任何构造函数, 系统会提供默认的`无参`构造函数. - 一旦
写了任何一个构造函数, 系统都不会提供默认的构造函数. - 可以通过
默认实参和重载默认构造函数的方式来提供默认构造函数. - 100%会被调用.
① 单纯的构造函数讨论, 不包括单例模式类似的解决方案
析构函数
- 析构函数名是 一个
~+ 类名. - 析构函数
没有返回值, 并且`不可加返回值类型. - 当
该类的对象销毁时, 会自动调用类的析构函数. - 当析构函数
私有时, 外部不能够调用,该类不能被新建对象 - 如果
不提供, 系统会提供默认的析构函数. - 析构函数
必须无参数.
对象
我们从广义上来理解一下 对象.
我们每一个人, 都是一个对象.
我们都具备人类的特征和能力.
我们每个都是具象的, 都是真实存在的.在C++中, 使用
类名 变量名;就能创建一个对象.
对象是"真实存在"的, 在我们的C++中, 它是占用内存的
类和对象的使用
#include <iostream>
#include <cstring>
class HadesString
{
// 默认是私有的访问权限
// private:
// 属性
char* _szStr;
int _iLen;
// 方法
public:
// 构造函数
HadesString()
{
std::cout << "HadesString()被调用" << std::endl;
_szStr = new char[100];
}
HadesString(char* str)
{
_iLen = strlen(str);
_szStr = new char[_iLen + sizeof(char)];
strcpy(_szStr, str);
}
// 析构函数
~HadesString()
{
std::cout << "~HadesString()被调用" << std::endl;
delete[] _szStr;
}
int& Len()
{
return _iLen;
}
char* GetString()
{
return _szStr;
}
};
int main()
{
HadesString str("Hello Hades!");
str.Len() = 10;
std::cout << str.GetString() << std::endl;
return 0;
}未完待续如有错误,请提出指正!谢谢.
本文由 花心胡萝卜 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: 2017-01-04 at 01:50 am