C++的面向对象编程。
C++库函数,函数重载,联合,私有成员和公有成员,静态数据成员和成员函数,友元类和友元函数,类函数,类模板和函数模板,内联函数,多重继承,多态性。
> 库函数
C++常用库函数- http://blog.youkuaiyun.com/sai19841003/article/details/7957115
> 函数重载
【C++拾遗】 C++函数重载、重写、重定义的区别- http://blog.youkuaiyun.com/xiejingfa/article/details/48496593
#include <iostream>
using namespace std;
//交换 int 变量的值
void Swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
//交换 float 变量的值
void Swap(float *a, float *b){
float temp = *a;
*a = *b;
*b = temp;
}
//交换 char 变量的值
void Swap(char *a, char *b){
char temp = *a;
*a = *b;
*b = temp;
}
//交换 bool 变量的值
void Swap(bool *a, bool *b){
char temp = *a;
*a = *b;
*b = temp;
}
int main(){
//交换 int 变量的值
int n1 = 100, n2 = 200;
Swap(&n1, &n2);
cout<<n1<<", "<<n2<<endl;
//交换 float 变量的值
float f1 = 12.5, f2 = 56.93;
Swap(&f1, &f2);
cout<<f1<<", "<<f2<<endl;
//交换 char 变量的值
char c1 = 'A', c2 = 'B';
Swap(&c1, &c2);
cout<<c1<<", "<<c2<<endl;
//交换 bool 变量的值
bool b1 = false, b2 = true;
Swap(&b1, &b2);
cout<<b1<<", "<<b2<<endl;
return 0;
}
> 内联函数inline
C语言inline与static详细讲解- http://www.cnblogs.com/xkfz007/articles/2370640.html
内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。
C++ 通过内联机制,既具备宏代码的效率,又增加了安全性,还可以自由操作类的数据成员,算是一个比较完美的解决方案。
“用函数内联取代宏”,宏在C++中基本是被废了.内联函数的功能和预处理宏的功能相似。
为什么要使用宏呢?因为函数的调用必须要将程序执行的顺序转移到函数所存放在内存中的某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方。这种转移操作要求在转去执行前要保存现场并记忆执行的地址,转回后要恢复现场,并按原来保存地址继续执行。因此,函数调用要有一定的时间和空间方面的开销,于是将影响其效率。而宏只是在预处理的地方把代码展开,不需要额外的空间和时间方面的开销,所以调用一个宏比调用一个函数更有效率。
但是宏也有很多的不尽人意的地方。
1、宏不能访问对象的私有成员。
2、宏的定义很容易产生二意性。
从 inline的作用来看,其放置于函数声明中应当也是毫无作用的:inline只会影响函数在translation unit(可以简单理解为C源码文件)内的编译行为,只要超出了这个范围inline属性就没有任何作用了。所以inline关键字不应该出现在函数声明 中,没有任何作用不说,有时还可能造成编译错误(在包含了sys/compiler.h的情况下,声明中出现inline关键字的部分通常无法编译通 过);
inline关键字仅仅是建议编译器做内联展开处理,而不是强制。在gcc编译器中,如果编译优化设置为-O0,即使是inline函数也不会被内联展开,除非设置了强制内联(__attribute__((always_inline)))属性。
内联函数和宏的区别在于,宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一些问题。
我们可以用Inline来定义内联函数,不过,任何在类的说明部分定义的函数都会被自动的认为是内联函数。
#include<iostream>
inline double square(double x){return x*x;}
int main()
{
using namespace std;
double a,b;
double c = 13.0;
a = square(5.0);
b = square(4.5+7.5);
cout<<"a="<<a<<",b="<<b<<endl;
cout<<"c="<<c<<endl;
cout<<"c squared="<<square(c++)<<endl;
cout<<"now c="<<c<<endl;
return 0;
}
> 联合,
结构与联合体是C语言中就已经存在的数据类型。C++语言对它们进行了扩展,最大的变化是允许在结构和联体中定义成员函数。
联合是用户定义的数据或类类型,在任何时间里,它只包含成员列表中的一个对象(当然,对象可以是数组或者类类型)。
联合提供了一种方式,能够规避C的类型系统,允许以多种类型来引用一个对象。联合声明的语法和结构体的语法一样,只不过语义相差很大。它们不是用不同的域来引用不同的存储器块,而是引用同一块存储块。
利用union可以用相同的存储空间存储不同型别的数据类型,从而节省内存空间。当访问其内成员时可用"."和"->"来直接访问。
在C中,必须使用union关键字来声明一个联合变量。在C++中,union关键字不是必需的:
union DATATYPE var2; // C声明联合变量
DATATYPE var3; // C++声明联合变量
#include <stdio.h>
union NumericType {
int iValue;
long lValue;
double dValue;
};
int main() {
union NumericType Values = { 10 }; // iValue = 10
printf("%d\n", Values.iValue);
Values.dValue = 3.1416;
printf("%f\n", Values.dValue);
}
联合体中的数据是共享相同的存储空间。
#include<iostream>
using namespace std;
union U1 {
int n;
char s[11];
double d;
};
union U2 {
int n;
char s[5];
double d;
};
int main() {
U1 u1;
U2 u2;
cout<<sizeof(u1)<<'\t'<<sizeof(u2)<<endl;
cout<<"u1各数据地址:\n"<<&u1<<'\t'<<&u1.d<<'\t'<<&u1.s<<'\t'<<&u1.n<<endl;
cout<<"u2各数据地址:\n"<<&u2<<'\t'<<&u2.d<<'\t'<<&u2.s<<'\t'<<&u2.n<<endl;
}
> 私有成员和公有成员
#include <iostream>
class Cat{
public:
void setWeight(int w){weight=w;}//设置重量
int print(){return weight;}//返回重量的大小
private:
int weight;
};
int main(){
Cat cat;
cat.setWeight(5);//设置cat的重量为5
cout<<"The cat's weight is "<<cat.print()<<endl;
return 0;
}
> 静态成员和静态成员函数
声明为static的类成员或者成员函数便能在类的范围内共同享,我们把这样的成员称做静态成员和静态成员函数。
静态成员函数与普通成员函数的差别就在于缺少this指针,没有这个this指针自然也就无从知道name是哪一个对象的成员了。
#include <iostream>
using namespace std;
class Student
{
public:
Student (char *name);
~Student();
public:
char name[30];
Student *next;
static Student *point;
};
Student::Student (char *name)
{
strcpy(Student::name,name);
this->next=point;
point=this;
}
Student::~Student ()//析构过程就是节点的脱离过程
{
cout<<"析构:"<<name<<endl;
if(point==this)
{
point=this->next;
cin.get();
return;
}
for(Student *ps=point;ps;ps=ps->next)
{
if(ps->next==this)
{
cout<<ps->next<<"|"<<this->next<<endl;
ps->next=next;//=next也可以写成this->next;
cin.get();
return;
}
}
cin.get();
}
Student* Student::point=NULL;
void main()
{
Student *c = new Student("marry");
Student a("colin");
Student b("jamesji");
delete c;
Student *fp=Student::point;
while(fp!=NULL)
{
cout<<fp->name<<endl;
fp=fp->next;
}
cin.get();
}
> 友元函数
友元是一种定义在类外部的普通函数,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。
友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样。
#include <iostream>
using namespace std;
class CObj
{
public:
CObj() : mX(0), mY(0) {}
friend class CFriend;
private:
void PrintData() const
{
cout << "mX = " << mX << endl
<< "mY = " << mY << endl;
}
int mX;
int mY;
};
class CFriend
{
public:
CFriend(int x, int y)
{
mObj.mX = x; //直接调用类CObj的私有数据成员
mObj.mY = y;
}
void ShowData() const
{
mObj.PrintData(); //直接调用类CObj的私有成员函数
}
private:
CObj mObj;
};
int main()
{
CFriend one(3, 4);
one.ShowData();
return 0;
}
> 虚函数,纯虚函数
虚函数: 就是允许被其子类重新定义的成员函数,子类重新定义父类虚函数的做法,可实现成员函数的动态覆盖(Override)。
纯虚函数: 是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”
#include<iostream>
using namespace std;
//基类对象
class Base
{
public:
//有virtual关键字,运行时多态
virtual void f(float x)
{
cout<<"Base::f(float)"<< x <<endl;
}
//无viratul关键字,不会发生运行时多态
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; //多态、覆盖
}
//子类与父类的函数同名,无virtual关键字,则为隐藏
void g(int x)
{
cout<<"Derived::g(int)"<< x <<endl; //隐藏
}
void h(float x)
{
cout<<"Derived::h(float)"<< x <<endl; //隐藏
}
};
int 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 无多态,调用自己的
// Bad : behavior depends on type of the pointer
pb->h(3.14f); // Base::h(float) 3.14 无多态,调用自己的
pd->h(3.14f); // Derived::h(float) 3.14 无多态,调用自己的
return 0;
}
> 多继承与多重继承
多继承是指一个子类继承多个父类。多继承对父类的个数没有限制,继承方式可以是公共继承、保护继承和私有继承,
不写继承方式,默认是private继承
多重继承特点总结如下:
(1)多重继承与多继承不同,当B类从A类派生,C类从B类派生,此时称为多重继承
(2)当实例化子类时,会首先依次调用所有基类的构造函数,最后调用该子类的构造函数;销毁该子类时,则相反,先调用该子类的析构函数,再依次调用所有基类的析构函数。
(3)无论继承的层级有多少层,只要它们保持着直接或间接的继承关系,那么子类都可以与其直接父类或间接父类构成 is a的关系,并且能够通过父类的指针对直接子类或间接子类进行相应的操作,子类对象可以给直接父类或间接父类的对象或引用赋值或初始化。
> 函数模板和类模板
区别在于函数模板和类模板的使用方式上:
函数模板在使用时不需要程序员指定类型,编译器在编译的时候会自动绑定;而类模板需要程序员手工指定,指定的方式是:类名字<类型>。
模板(template)是一个将数据类型参数化的工具。模板分为函数模板和类模板两种。
在定义模板的时候不说明某些函数参数或者数据成员的类型,而将它们的数据类型作为模板参数。在使用模板时根据实参的数据类型确定模板参数即数据类型,从而得到模板的一个实例。
类模板是这样一种通用的类:在定义类时不说明某些数据成员、成员函数的参数及返回值的数据类型。类是对对象的抽象,而类模板是对类的抽象,及更高层次上的抽象。类模板称为带参数的类,也称为类工厂(class factory),它可用来生成多个成员相同而某些数据成员、成员函数的参数及返回值的数据类型不同的类型参数。
> 函数模板
#include <iostream.h>
template <typename T> //或写成:template <typename T> ;template <class T>
T abs(T val) {
return val<0 ? -val : val;
}
int main() {
int i=100;
cout<<abs(i)<<endl; //类型参数T替换为int
long l=-12345L;
cout<<abs(l)<<endl; //类型参数T替换为long
float f=-125.78F;
cout<<abs(f)<<endl; //类型参数T替换为float
return 0;
}
> 类模板
#include <iostream.h>
template <class T1, class T2> //使用2个类型参数
class MyTemClass{ //定义类模板
private:
T1 x;
T2 y;
public:
MyTemClass(T1 a, T2 b) {x=a; y=b;} //构造函数
void ShowMax(){ //输出最大的数据成员
cout<<"MaxMember="<<(x>=y ? x : y)<<endl;
}
};
int main(){
int a=100;
float b=123.45F;
MyTemClass<int, float> mt(a,b); //声明类模板的对象
mt.ShowMax();
return 0;
}
//静态数组初始化
#include <iostream>
using namespace std;
int array1[5]={1,2,3};
static int array2[5]={1};
int main(){
int arr1[5]={2};
static int arr2[5]={1,2};
int n;
cout <<"global:\n";
for(n=0; n<5; n++)
cout <<" " <<array1[n];
cout <<"\n global static:\n";
for(n=0; n<5; n++)
cout <<" " <<array2[n];
cout <<"\n local:\n";
for(n=0; n<5; n++)
cout <<" " <<arr1[n];
cout <<"\n local static:\n";
for(n=0; n<5; n++)
cout <<" " <<arr2[n];
cout <<endl;
return 0;
}
//二维数组初始化 ,二维数组的初始化 -http://blog.youkuaiyun.com/chenshijun0101/article/details/6640377/
#include <iostream>
using namespace std;
//二维数组的长度
#define kI 3
#define kJ 4
/** 打印二维数组元素 */
void printfArray(int array[][kJ], int x) {
for (int i = 0; i < x; i++) {
for (int j = 0 ; j < kJ; j++) {
printf("%d\t",array[i][j]);
}
printf("\n");
if (i == x-1) {
printf("\n");
}
}
}
/**
利用for循环对二维数组进行初始化
*/
void initArray(int array[][kJ]) {
for(int i = 0 ; i < kI; i++) {
for (int j = 0; j < kJ; j++) {
array[i][j] = i*j;
}
}
}
int main(int argc, const char * argv[]) {
// insert code here...
// printf("Hello, World!\n");
//定义一个二维数组
//对数组元素进行直接初始化,少于其3*4的个数后面用0补充,多余的舍去
int a[3][4] = {1,2,2,3,4,4,4,5,5,5,4,5}; //分配内存的同时初始化数组
printfArray(a,3);
printf("===============================\n");
int b[][kJ] = {1,2,3,4,4,5,6}; //对二维数组进行初始化的时候,至少要求后面的数组个数是确定的。
printfArray(b,2);
printf("================================\n");
int c[kI][kJ];
initArray(c);
printfArray(c, kI);
return 0;
}