对象的初始化、复制
初始化类型
默认初始化
例如
HaveAll one;
直接初始化
注意
赋值和初始化不同,是对已经存在的对象进行的,含义是清除对象当前的值,写入新的值来代替
拷贝初始化
例如
HaveAll two = one;
HaveAll four = 4;
列表初始化
例如
HaveAll arr2[3] = {8, 9};
默认构造函数(可不提供实参就能调用的构造函数)
例如,HaveAll()是HaveAll 类的默认构造函数
拷贝构造函数
浅复制
例如
X one;
X two(one);(用one初始化同类型对象two)
浅复制可能出错,为了避免编译器合成不恰当的浅复制行为,可以自己定义拷贝构造函数,对包括指针和引用在内的成员进行恰当的初始化
拷贝构造函数的一般形式是X(X&)或者X(const X&)
const X a;
X b(a);
X c(b);
运算符重载
这个很简单那,我就不用按课件上的来了,我直接说按我的理解的。
定义了一个数据类,例如一个时间类
class time//时间类
{
private:
int year;
int month;
int day;
public:
time(){};
time(int x,int y,int z):year(x),month(y),day(z){};
int getYear(){return year;}
int getMonth(){return month;}
int getDay(){return day;}
void setYear(int newYear)
{
year=newYear;
}
void setMonth(int newMonth)
{
month=newMonth;
}
void setDay(int newDay)
{
day=newDay;
}
friend istream &operator>>(istream &in, time &A);
friend ostream &operator<<(ostream &out, time &A);
friend time operator+(const time &A,const time &B);
bool operator<(const time &A);
};
可以看出,时间类里包含了年月日三个量,如果因为某种要求,我需要对进行计算,那么就需要对运算符进行重载,就是定义运算的规则
time operator+(const time &A,const time &B)//承载加号运算符
{
time C;
C.day=A.day+B.day;
C.month=A.month+B.month;
C.year=A.year+B.year;
if(C.day>30)
{
int n;
n=C.day/30;
C.day=C.day-30;
C.month=C.month+n;
}
if(C.month>12)
{
int m;
m=C.month/12;
C.month=C.month-12;
C.year=C.year+m;
}
return C;
}
bool time::operator<(const time &A)//重载小于号运算符
{
if((this->year<A.year)||(this->year==A.year&&this->month<A.month)||(this->year==A.year&&this->month==A.month&&this->day<A.day))
{
return true;
}
else return false;
}
常重载的运算符有
+ - * / % == != > < >= <= >> << 等等
组合与继承
组合
将一个类的对象作为另一个类的成员,被称作组合或包含
对象成员的初始化
例子
{
private:
int year;
int month;
int day;
public:
time(){};
time(int x,int y,int z):year(x),month(y),day(z){};
.......
}
继承
继承:在已有类的基础上创建新类的过程
被继承的已有类称为基类;
继承得到的新类称为派生类;
派生类可以再被继承,这样构成的层次结构称为继承层次
例子
class student
{
string name;
int student_id;
string department;
public:
student(string nm, int id, string dp);
void print()const;
};
class grad_student:public student//在student的基础上的添加
{
string thesis;
public:
grad_student(string nm, int id, string dp, string th);
void print()const;
};
语法形式
class 派生类名 : 基类名表
{
数据成员和成员函数声明
};
三种
public 公有继承
private 私有继承
protected 保护继承
PS:派生类都不能直接使用基类的私有成员
公有继承可以继承积累中出了private的所有内容
在派生类中调用基类的函数
class Person
{
string name;
int age;
string sex;
public:
void set() {
cout<<"name\tage\tsex"<<endl;
cin>>name>>age>>sex;
}
void show() {
cout<<name<<" "<<age<<" "<<sex<<endl;
}
};
class student :public Person
{
string no;
string zhuanye;
string t_class;
float score;
public:
void set(){ //隐藏了基类中的同名成员
Person::set(); //调用继承于基类的成员函数访问继承于基类的数据成员
cout<<"zhuanye\tt_class\tscore"<<endl;
cin>>zhuanye>>t_class>>score;
}
void show() {
Person::show();
cout<<zhuanye<<" "<<t_class<<" "<<score<<endl;
}
};
或
class Person
{
string name;
int age;
string sex;
public:
void set_p() {
cout<<"name\tage\tsex"<<endl;
cin>>name>>age>>sex;
}
void show_p() {
cout<<name<<" "<<age<<" "<<sex<<endl;
}
};
class student :public Person
{
string no;
string zhuanye;
string t_class;
float score;
public:
void set_t(){
set_p(); //调用继承于基类的成员函数访问继承于基类的私有数据成员
cout<<"zhuanye\tt_class\tscore"<<endl;
cin>>zhuanye>>t_class>>score;
}
void show_t() {
show_p();
cout<<zhuanye<<" "<<t_class<<" "<<score<<endl;
}
};
基类的初始化
派生类构造函数声明为
派生类构造函数 ( 变元表 ) : 基类 ( 变元表 ) , 对象成员
重名数据成员
class base
{ public :
int a , b ;
} ;
class derived : public base
{ public :
int b , c ;
} ;
void f ()
{ derived d ;
d . a = 1 ;
d . base :: b = 2 ;
d . b = 3 ;
d . c = 4 ;
};
重名函数
class A
{ public:
int a1, a2 ;
A( int i1=0, int i2=0 ) { a1 = i1; a2 = i2; }
void print()
{ cout << "a1=" << a1 << '\t' << "a2=" << a2 << endl ; }
};
class B : public A
{ public:
int b1, b2 ;
B( int j1=1, int j2=1 ) { b1 = j1; b2 = j2; }
void print() //定义同名函数
{ cout << "b1=" << b1 << '\t' << "b2=" << b2 << endl ; }
void printAB()
{ A::print() ; //派生类对象调用基类版本同名成员函数
print() ; //派生类对象调用自身的成员函数
}
};
虚函数与多态
多态性是指一个名字,多种语义;或界面相同,多种实现。
冠以关键字 virtual 的成员函数称为虚函数
虚函数和基类指针
一个虚函数,在派生类层界面相同的重载函数都保持虚特性
虚函数必须是类的成员函数
虚函数可以是另一个类的友元
析构函数可以是虚函数,但构造函数不能是虚函数
虚函数的重载特性
在派生类中重载基类的虚函数要求函数名、返回类型、参数个数、
参数类型和顺序完全相同
如果仅仅返回类型不同,C++认为是错误重载
如果函数原型不同,仅函数名相同,丢失虚特性
例子
class base
{ public :
virtual void vf1 ( ) ;
virtual void vf2 ( ) ;
virtual void vf3 ( ) ;
void f ( ) ;
} ;
class derived : public base
{ public :
void vf1 ( ) ; // 虚函数
void vf2 ( int ) ; // 重载,参数不同,虚特性丢失
void f ( ) ; // 非虚函数重载
} ;
void g ( )
{
derived d ;
base * bp = & d ; // 基类指针指向派生类对象
bp -> vf1 ( ) ; // 调用 deriver :: vf1 ( )
bp -> vf2 ( ) ; // 调用 base :: vf2 ( )
bp -> f ( ) ; // 调用 base :: f ( )
} ;
纯虚函数和抽象类
纯虚函数是一种特殊的虚函数,
在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。
纯虚函数是一个在基类中说明的虚函数,在基类中没有定义, 要求任何派生类都定义自己的版本
纯虚函数为各派生类提供一个公共界面
纯虚函数说明形式:
virtual 类型 函数名(参数表)= 0 ;
一个具有纯虚函数的基类称为抽象类