这是我面向对象(我没有!)课的笔记,老师讲到哪,我就记到哪,绝不预习!
o( ̄ε ̄*)
现在还没讲完呢。
每周二更新(大概)
int main()
{
int *p1=new int;//p指向一个数,这个数字是随机的
int *p2=new int(2);//p指向一个数字,这个数字等于2
int *p3=new int[5];//p指向一个大小为5的数组
delete p1, p2, []p3;//结束前千万别忘了delete哟
}
在一个类内:
public:公有成员,对象可直接访问、修改的成员
private:私有成员,在类内可直接访问,但对象无法直接访问
protected:基类对象不能直接调用,但派生类的定义中可以直接调用。
在继承中:
public:公有继承,基类成员类型不变地继承到派生类中
private:私有继承,基类成员类型在派生类中全部变为私有
protected:基类所有public成员全变为protected,其余类型不变。
在对象中,this指向该对象。
class A
{
int x;
public:
A(int x=0){this->x=x;}
};
class A
{
static int b;
public:
int getb(){return b;}
static void print(){cout<<"A"<<endl;}
};
class B:public A
{
static int d;
public:
int getd(){return d;}
};
/** 下面是static成员变量的初始化 **/
int A::b=0;//或int B::b=0;
int B::d=0;
int main()
{
A::print(); //使用方法一
A a; a.print(); //使用方法二
}
将基类中的 protected 或 public 调整成 public 或 protected 或 private。
对 private 则没有权限调整。
class A
{
public:
int x;
protected:
int y;
};
class B:public A
{
public:
using A::y;
protected:
using A::z;
};
公有继承(public)时:
class A
{
int x;
public:
void set(int x=0){this->x=x;}
int getx(){return x;}
};
class B:public A
{
int y;
public:
void set(int x=0, int y=0){A::set(x);this->y=y;}
int getx(){return x;}
}
void main()
{
A a; B b;
a.set(10); b.set(20,30);
cout<<a.getx()<<endl;//10
cout<<b.getx()<<endl;//20
a=b;
cout<<a.getx()<<endl;//20
A *p=&b;
p->set(40);//这是A类的set(),set(40,50)是错误的。
cout<<p->getx()<<endl;//40
}
class A
{
int x;
public:
A(int x=0):x(x){}
A(A &a):x(a.x){}
~A(){}
int getx(){return x;}
};
class B:public A
{
int y;
public:
B(int x=0, int y=0):A(x),y(y){} //构造时先构造基类
/**下面是赋值构造函数的三种写法**/
B(B &b):A(b.getx()),y(b.y){} //朴素型
B(B &b):A(b),y(b.y){} //粗犷型,用到赋值兼容,需要是公有继承
B(B &b):y(b.y){} //爱咋咋地型。相当于B(B&b):A(),y(b.y){}
~B(){} //先执行~B(),再执行成员变量的析构函数(如果有的话),再执行~A()
};
int main()
{
A *p=new B(1,2);
delete p; //只撤销A类对象
}
单继承:这个派生类只有一个基类
多继承:这个派生类有不止一个基类
重复继承:如上图三的第三张图
class A
{
int x;
public:
A(int x=0):x(x){}
int getx(){return x;}
};
class B:public A
{
int y1;
public:
B(int x=0, int y=0):A(x),y1(y){}
int gety1(){return y1;}
};
class C:public A
{
int y2;
public:
C(int x=0, int y=0):A(x),y2(y){}
int gety2(){return y2;}
};
class D:public B,public C//B,C有不同的A空间
{
int z;
public:
D(int a, int b, int c, int d, int e):B(a,b),C(c,d),z(e){}
int getz(){return z;}
};
int main()
{
D d(1,2,3,4,5);
cout<<d.B::getx()<<d.gety1()<<d.C::getx()<<d.gety2()<<d.getz()<<endl;
//12345
}
虚拟继承:增加关键字virtual,让B、C有同一个A空间
class A
{
int x;
public:
A(int x=0):x(x){}
int getx(){return x;}
};
class B:public virtual A//增加关键字virtual
{
int y1;
public:
B(int x=0, int y=0):A(x),y1(y){}
int gety1(){return y1;}
};
class C:public virtual A//增加关键字virtual
{
int y2;
public:
C(int x=0, int y=0):A(x),y2(y){}
int gety2(){return y2;}
};
class D:public B,public C//B,C有同一个的A空间
{
int z;
public:
D(int a, int b, int c, int d, int e):A(a),B(a,b),C(c,d),z(e){}//注意多了A()
int getz(){return z;}
};
int main()
{
D d(1,2,3,4,5);
cout<<d.getx()<<d.gety1()<<d.getx()<<d.gety2()<<d.getz()<<endl;
//12145
}
重复继承和虚拟继承都属于多继承。
重命名?
相同的消息,发送给不同的对象,产生不同的结果
若基类指针指向派生类,用这一指针调用的函数是基类的;如果用虚函数,则可以调用派生类的同名覆盖函数。
举个例子:
class A1
{
public:
void f(){cout<<"f() from A1"<<endl;}
};
class A2
{
public:
virtual void g(){cout<<"g() from A2"<<endl;} //虚函数
};
class B:public A1, public A2
{
public:
void f(){cout<<"f() from B"<<endl;}
void g(){cout<<"g() form B"<<endl;}
};
void main()
{
A1 *p1=new B;
A2 *p2=new B;
p1->f(); p2->g();
delete p1, p2;
}
输出:
f() from A1
g() form B
注意此时 p2 指针调用了派生类 B 的 g()。
析构函数可以是虚函数,构造函数不能是虚函数。
若基类一个函数是虚的,那么派生类中同名覆盖函数默认成虚的。
请问下列调用的分别是哪个类的哪个函数:
普通函数调用虚函数、虚函数调用普通函数、虚函数调用虚函数、构造函数调用虚函数、虚函数调用构造函数、析构函数调用虚函数、虚析构函数调用析构函数、虚函数调用构造函数调用虚函数…
╯(゚Д゚)╯╧╧
吭吭,一般带虚函数的函数调用函数遵循就近原则。
下面就小试一下吧~
class A { public: void f(){cout<<"f from A"<< endl;} virtual void g(){ f(); cout<<"g from A"<< endl;} }; class B:public A { public: void f(){cout<<"f from B"<< endl;} void g(){ f(); cout<<"g from B"<< endl;} }; void main() { A *p=new B; p->g(); delete p; }输出: f from B g from B |
class A { public: virtual void f(){cout<<"f from A"<< endl;} void g(){ f(); cout<<"g from A"<< endl;} }; class B:public A { public: void f(){cout<<"f from B"<< endl;} void g(){ f(); cout<<"g from B"<< endl;} }; void main() { A *p=new B; p->g(); delete p; }输出: f from B g from A |
class A { public: A(){f();} virtual void f(){cout<<"f from A"<< endl;} }; class B:public A { public: B():A(){} void f(){cout<<"f from B"<< endl;} //virtual ~B(){cout<<"del from B"<< endl;} }; void main() { A *p=new B; delete p; }输出: f from A 解释:多态是建立在对象已经构造完成后的状态下的, 由于f()是在构造函数中调用的,virtual还没起作用。 |
class A { public: virtual ~A(){cout<<"del from A"<< endl;} }; class B:public A { public: ~B(){cout<<"del from B"<< endl;} }; void main() { A *p=new B; delete p; }输出: del from B del from A |
对于class A{int x; public: virtual void f(){} };
来说,A、B分别占多大空间呢?(int空间为4)
class B:public A{int y; public: void f(){} };
答案:8、12.
如果没有 virtual 的话,应该是 4、8。
加virtual后生成了虚函数表,这个表的首地址,一个void* 类型,就是这4的原因。
既然虚就一虚到底。
纯虚函数virtual void f()=0;
有纯虚函数的类叫抽象类,不能有对象,但可以有指针。
为什么我没有对象——因为我有纯虚函数!
有些函数的参数类型不同,但想做的操作类似。
比如同样是求最大值,但参数分别是 int、double、char、long,难道要对于每种参数都写个函数吗?
程序猿们不想些那么多类似的代码,于是就有了模板。
模板,也称泛型。包括函数模板和类模板。模板有自定义的(自己写的),还有标准的(系统自带的)。
模板不会改变运行效果,只是改变代码结构。
于是就写成这样:
//函数模板定义:
template<typename T>
T GetMax(T a, T b){ return a>b?a:b; }
//使用
int main()
{
int a, b=1, c=2;
a=GetMax<int>(b,c);
a=GetMax(b,c);//依据参数自动判断
}
函数模板由 template 开始,到函数结束结束。
template 是关键字,typename T 是模板参数,typename 是参数类型,T 是形式参数名称(类型参数)。
使用 int a=GetMax
typename 还可写成 class。如 template
。建议都用 class 。
更多例子:
///例1
template<class T, int SIZE>
T GetMax(T *arr)
{
T m=arr[0];
for(int i=1; i<SIZE; ++i)
if(m<arr[i]) m=arr[i];
return max;
}
int a[200];
void main()
{
for(int i=0; i<200; ++i) a[i]=(i*2333)%666;
int m=GetMax<int,200>(a);
cout<<m<<endl;
}
///例2
template<class T1, class T2>
T1 Func(T2 a, T2 b){ return a>b?T1(1):T1(0); }
下面说一下类模板。
它长这个样子:
template<class T1, class T2>
class Pair
{
T1 a; T2 b;
public:
Pair(){}
Pair(T1 a, T2 b);
T1 first(){return a;}
T2 second();
};
//成员函数的类外定义
template<class T1, class T2>
T2 Pair<T1,T2>::second(){return b;}
//构造函数的类外定义
template<class T1, class T2>
Pair<T1,T2>::Pair(T1 x, T2 y){a=x;b=y;}
//使用
void main()
{
Pair<int,double> a(1,3.14);
cout<<a.first()<<" "<<a.second()<<endl;
}
类模板可以有多个类型参数,可提供缺省值(如
我觉得 queue、vector 这样的就是模板吧。
假如定义一个三维向量类:
class Vector { int x, y, z; public: Vector(int x=0, int y=0, int z=0):x(x),y(y),z(z){} int getx(){return x;} int gety(){return y;} int getz(){return z;} };
我们想求向量的加减乘,于是我们定义下列函数:
Vector add(Vector a, Vector b){return Vector(a.getx()+b.getx(),a.gety()+b.gety(),a.getz()+b.getz()); } Vector sub(Vector a, Vector b){return Vector(a.getx()-b.getx(),a.gety()-b.gety(),a.getz()-b.getz()); } int mul1(Vector a, Vector b){return a.getx()*b.getx()+a.gety()*b.gety()+a.getz()*b.getz();} //点乘 Vector mul2(Vector a, Vector b){return Vector(a.gety()*b.getz()-a.getz()*b.gety(),a.getz()*b.getx()-a.getx()*b.getz(),a.getx()*b.gety()-a.gety()*b.getx()); } //叉乘
假如现在有 a,b,c,d,e 这几个向量,我们想求 (a+b^c-d)*e,其中 ‘*’ 表示点乘,‘^’ 表示叉乘,那么我们需要写成:
mul2(sul(add(a,mul1(b,c)),d),e)
好繁琐。所以我们想简化表达,想写成
(a+b^c-c)*e
怎么做呢?重载,也就是定义 ±*^ 运算。
这样写:
class Vector
{
int x, y, z;
public:
Vector(int x=0, int y=0, int z=0):x(x),y(y),z(z){}
int getx(){return x;}
int gety(){return y;}
int getz(){return z;}
};
Vector operator+(Vector a, Vector b){......}
Vector operator-(Vector a, Vector b){......}
int operator*(Vector a, Vector b){......}
Vector operator^(Vector a, Vector b){......}
如果实在闲的蛋疼,a+b 也可写成 operator+(a,b) 。
不过好像 ‘^’ 的优先级没 ‘±’ 大,要写成
(a+(b^c)-c)*e
重载还没学完,下周再更!