C++ 重点总结
public/private/protected 修饰符
public和private用来支持类的封装特性,使用public修饰的成员可以在类的外部进行访问,使用private修饰的类成员只能在类的内部和友元中访问。
protected用来支持类的继承特性,用protected修饰的成员可以被派生类对象访问,不能被用户代码(类外)访问。
#include <iostream>
using namespace std;
class Shape
{
public:
void SetWidth(int w)
{
width = w;
}
void SetHeight(int h)
{
height = h;
}
// 如果这里用private修饰,那么在Rectangle中的GetArea方法中就无法使用width和height这两个私有属性
protected:
//private:
int width;
int height;
};
/* 子类的继承也有public, protected, private三种继承方式
* 继承的过程中会改变基类成员的访问属性, 改变规则如下:
* public继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:public, protected, private
* protected继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:protected, protected, private
* private继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:private, private, private
* 也就是说从访问权限来讲,public > protected > private, public仅可以被protected或private改变,
* protected仅可以被private改变, private不可被改变。
* 如果不显式的使用修饰符,那么默认为private
*/
class Rectangle: public Shape
{
public:
int GetArea()
{
cout << "Rectangle Total area: " << (width * height) << endl;
}
};
/* 因为使用protected 继承, 所以在main中无法再使用SetWidth() 和 SetHeight()方法
* 这里使用构造函数中调用这两个方法来初始化
*/
class RightTriangle: protected Shape
{
public:
int GetArea()
{
cout << "Right Triangle Total area: " << (width * height / 2) << endl;
}
RightTriangle()
{
SetWidth(4);
SetHeight(5);
}
};
int main(void)
{
Rectangle rect;
rect.SetWidth(5);
rect.SetHeight(7);
rect.GetArea();
RightTriangle triangle;
/* 这两个方法变成了protected,所以无法使用 */
//triangle.SetWidth(4);
//triangle.SetHeight(5);
triangle.GetArea();
return 0;
}
friend(友元)修饰符
引用的用法(&)
引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。
引用的声明方法:类型标识符& 引用名=目标变量名;
说明:
- &在此不是求地址运算,而是起标识作用
- 类型标识符是指目标变量的类型
- 声明引用时,必须同时对其进行初始化
- 引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名
- 声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。故:对引用求地址,就是对目标变量求地址。&ra与&a相等
- 不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名
引用在参数中的实例
#include <iostream>
using namespace std;
/* 这里从用法上讲,引用可以理解为指针但是少去了类似*p这种繁琐的写法
* 实际上,不能把指针和引用混为一谈,这两者有着本质的区别
*/
void swap(int& x, int& y)
{
int temp;
temp = x;
x = y;
y = temp;
return;
}
int main ()
{
int a = 1;
int b = 2;
swap(a, b);
return 0;
}
引用在返回值中的实例
#include <iostream>
using namespace std;
double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};
/* 需要注意,即便是引用,也无法返回局部变量
*/
double& setValues(int i)
{
return vals[i];
}
int main(void)
{
for ( int i = 0; i < 5; i++ ) {
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
setValues(1) = 20.23;
setValues(3) = 70.8;
for ( int i = 0; i < 5; i++ ) {
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
return 0;
}
泛型编程之模板
定义方式
template <class 形参名, class 形参名, ......> 返回类型 函数名(参数列表)
{
函数体
}
template <typename 形参名,typename 形参名,......> 返回类型 函数名(参数列表)
{
函数体
}
函数模板
#include <iostream>
#include <string.h>
using namespace std;
template <typename T>
inline T const& Max(T const& a, T const& b)
{
return a < b ? b : a;
}
int main()
{
int i = 1, j = 2;
float m = 3.14, n = 1.238;
/*
* 可以进行实参推演
*/
cout << "max int: " << Max(i, j) << endl;
cout << "max float: " << Max(m, n) << endl;
return 0;
}
类模板
#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
using namespace std;
/*
* 模板类
* 其中bool empty() 后面加了const,const的含义是函数体中不修改类中的数据, 相当于传入了 const self
* 这种用法可以用来保证某个方法不修改类中的字段,并且便于阅读
* 其中vector本身就是一个模板类
*/
template <class T>
class Stack
{
private:
vector<T> elems;
public:
void push(T const& val);
void pop();
T top() const;
bool empty() const
{
return elems.empty();
}
};
/*
* 在类的外部定义模板类的模板方法
*/
template <class T>
void Stack<T>::push(T const& elem)
{
elems.push_back(elem);
}
template <class T>
void Stack<T>::pop()
{
if (elems.empty())
{
throw out_of_range("Stack<>::pop(): empty stack");
}
elems.pop_back();
}
/*
* 声明为const类型,表明方法内部不会修改类中的字段
*/
template <class T>
T Stack<T>::top() const
{
if (elems.empty())
{
throw out_of_range("Stack<>::top(): empty stack");
}
return elems.back();
}
int main()
{
try
{
/*
* 对于模板类,必须为模板形参显式指定实参,类模板的形参不存在实参推演的
*/
Stack<int> intStack;
Stack<string> stringStack;
intStack.push(7);
cout << intStack.top() << endl;
stringStack.push("hello");
cout << stringStack.top() << std::endl;
stringStack.pop();
stringStack.pop();
}
catch (exception const &ex)
{
cerr << "Exception: " << ex.what() << endl;
return -1;
}
}