//函数模板
template <typename T>
int compare(T &v1, T&v2) {}
引用 http://www.cnblogs.com/Mr-xu/archive/2012/08/07/2626973.html
0.基本特性
int a;
int &ra = a; // 引用必须初始化,它只是某个变量的别名(没有自己的存储空间)
ra = 1; // 对引用的修改就是对原变量的修改
1.引用作为参数
目的:避免参数值拷贝,提高效率。
2.引用作为返回值
目的:避免拷贝;返回同一个变量,有利于做链式操作。
场景:返回值做为左值时必须用引用; count << "hello" << end; // 流操作符 赋值操作
注意:
1.局部变量不能做为引用返回(变量的生命周期已经结束)
2.不要返回函数内的new分配的内存的引用,申请的内存不好释放。
int &func(const String &rb); // 引用做为形参,函数体中对形参的修改就是对外部调用的实参的修改。没有拷贝一份实参,提高了效率
操作符重载 http://www.cnblogs.com/xiangxiaodong/archive/2012/02/12/2348144.html
class Person{
private:
int age;
public:
Person(int a) {age = a;}
bool <span style="color:#ff0000;"><strong>operater==</strong></span> (const Person &rb); // 定义
}
// 做为类的成员函数来实现
bool Person::operator== const Person &rb
{
if (<span style="color:#ff0000;">this</span>.age == rb.age) return true;
return false;
}
// 非成员函数的实现
bool operator== (Person &<span style="color:#ff0000;">ra</span>, Person &rb)
{
if (<span style="color:#ff0000;">ra</span>.age == rb.age) return true;
return false;
}
// 使用
Person a(10);
Person b(20);
if (a == b) ; // a对象调用比较运算,b做为参数
virtual虚函数
0.目的:
子类覆盖父类的方法。
所以:关键字在对象环境中才有意义
虚函数是运行时确定的。
因此:静态成员函数(针对一个类非对象),构造函数(对象还没有生成),内联函数(编译期间确定) 都不能声明为virtual的。
1.实现:
父类中被覆盖的方法前面加此关键字。子类该方法默认带这个关键字。
表面子类继承了父类的函数,但要重写override它(函数定义一模一样,允许返回值不同)。
2.注意:
基类的指针调用函数,有virtual的调用子类的函数,否则调用基类的函数。
用子类的指针调用,一律调用子类的函数。
//根据不同子类构造的基类指针,调用相应子类的方法,称为多态。虚函数通过指针或者引用来实现多态。
virtual void foo()=0; // 纯虚函数,拥有它的类为抽象类,提供了多态的接口。
#include <iostream.h>
class Base
{
public:
virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
void g(float x){ cout << "Base::g(float) " << x << endl; }
void h(float x){ cout << "Base::h(float) " << x << endl; }
};
class Derived : public Base
{
public:
virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
void g(int x){ cout << "Derived::g(int) " << x << endl; }
void h(float x){ cout << "Derived::h(float) " << x << endl; }
};
void main(void)
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
// Good : behavior depends solely on type of the object
pb->f(3.14f); // Derived::f(float) 3.14
pd->f(3.14f); // Derived::f(float) 3.14
// Bad : behavior depends on type of the pointer
pb->g(3.14f); // Base::g(float) 3.14
pd->g(3.14f); // Derived::g(int) 3 (surprise!)
// Bad : behavior depends on type of the pointer
pb->h(3.14f); // Base::h(float) 3.14 (surprise!)
pd->h(3.14f); // Derived::h(float) 3.14
}
函数的重载
0.目的:
根据参数的区别来调用同一类函数。
1.实现:
在一个类中实现几个函数名相同,参数不同的函数。
指针
1. 利用形参修改指针的值
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(sizeof(char) * num);
}
void Test(void){
char *str=NULL;
GetMemory(&str, 100);
strcpy(str,"hello world");
printf(str);
}
类
C++空类默认的成员函数
class Empty
{
public:
Empty(); // 缺省构造函数
Empty( const Empty& ); // 拷贝构造函数
~Empty(); // 析构函数
Empty& operator=( const Empty& ); // 赋值运算符
Empty* operator&(); // 取址运算符
const Empty* operator&() const; // 取址运算符 const
};
String类的实现
class String
{
public:
String(const char *str = NULL); // 普通构造函数
String(const String &other); // 拷贝构造函数
~ String(void); // 析构函数
String & operate =(const String &other); // 赋值函数
private:
char *m_data; // 用于保存字符串
};
//普通构造函数
String::String(const char *str)
{
if(str==NULL)
{
m_data = new char[1]; // 得分点:对空字符串自动申请存放结束标志'\0'的空 //加分点:对m_data加NULL 判断
*m_data = '\0';
}
else
{
int length = strlen(str);
m_data = new char[length+1]; // 若能加 NULL 判断则更好
strcpy(m_data, str);
}
}
// String的析构函数
String::~String(void)
{
delete [] m_data; // 或delete m_data;
}
//拷贝构造函数
String::String(const String &other) // 得分点:输入参数为const型
{
int length = strlen(other.m_data);
m_data = new char[length+1]; //加分点:对m_data加NULL 判断
strcpy(m_data, other.m_data);
}
//赋值函数
String & String::operate =(const String &other) // 得分点:输入参数为const型
{
if(this == &other) //得分点:检查自赋值
return *this;
delete [] m_data; //得分点:释放原有的内存资源
int length = strlen( other.m_data );
m_data = new char[length+1]; //加分点:对m_data加NULL 判断
strcpy( m_data, other.m_data );
return *this; //得分点:返回本对象的引用
}
const
1. 修饰为常量
A const int* a = &b; //指针指向的是常量,但指针可变。
B const* int a = &b; //指针是常量,指向的值可变
C const int* const a = &b; //a和*a都是const,常量和指针的值都不能改变
D int const* const a = &b; //a和*a都是const,常量和指针的值都不能改变
extern
sizeof()的用法
sizeof操作符的结果类型是size_t,它在头文件 中typedef为unsigned int类型。
1. sizeof(p) = 4; // 指针的大小为4字节,数组做参数时沦为指针类型,其大小为4.
2. char str[] = "abcd"; // sizeof(str) = 5, 得到静态数组的大小,包括字串结束符;区别:strlen(str)=4;求字串的大小,不包括结束符。
对齐
目的:提高CPU存储变量的速度
实现:
1.系统默认对齐 == 每个变量的偏倚地址是此变量大小的倍数 && 总空间大小是最大变量大小的倍数
struct MyStruct
{
char dda; //偏移量为0,满足对齐方式,dda占用1个字节;
double dda1;//下一个可用的地址的偏移量为1,不是sizeof(double)=8 的倍数,VC需要补足7个字节满足对齐方式,dda1存放在偏移量为8的地址上,它占用8个字节。
int type;//下一个可用的地址的偏移量为16,是sizeof(int)=4的倍数,满足int的对齐方式,所以不需要VC自动填充,type存放在偏移量为16的地址上,它占用4个字节
};//所有成员变量都分配了空间,空间总的大小为1+7+8+4=20,不是结构
//的节边界数(即结构中占用最大空间的类型所占用的字节数sizeof(double)=8)的倍数,所以需要填充4个字节。
所以该结构总的大小为:sizeof(MyStruc)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的,没有放任何有意义的东西。
2.自定义对齐
n字节对齐 == 变量存放的起始地址的偏移量为min(n, 默认值)
#pragma pack(push) //保存对齐状态
#pragma pack(4) //设定为4字节对齐
struct test
{
char m1;
double m4;
int m3;
};
#pragma pack(pop)//恢复对齐状态
以上结构的大小为16,下面分析其存储情况,首先为m1分配空间,其偏移量为0,满足我们自己设定的对齐方式(4字节对齐),m1占用1个字节。接着开始为 m4分配空间,这时其偏移量为1,需要补足3个字节,这样使偏移量满足为n=4的倍数(因为sizeof(double)大于n),m4占用8个字节。接着为m3分配空间,这时其偏移量为12,满足为4的倍数,m3占用4个字节。这时已经为所有成员变量分配了空间,共分配了16个字节,满足为n的倍数。如果把上面的#pragma pack(4)改为#pragma pack(16),那么我们可以得到结构的大小为24。
1. 数组的大小要求为编译期间常量
unsigned int temp = 3;
unsigned int const size = temp;
char str[ size ]; // 编译错误,运行时才知道数组的大小。如果unsigned int const size = 3; char str[size]; 这样定义OK。
int id[sizeof(unsigned long)]; // 这个对。sizeof是编译时运算符,编译时就确定了可以看成和机器有关的常量。
BOOL型变量:if(!var)
int型变量: if(var==0)
float型变量:const float EPSINON = 0.00001; if ((x >= - EPSINON) && (x <= EPSINON)
指针变量: if(var==NULL)
模板
1.函数模板
template <typename T>
int compare(T &v1, T&v2) {...}
2.类模板
eg. vector, map
template <class Type>
class myQueue:Queue<Type>
{
public:
void push(const Type &); ...
}