遗漏知识点:函数默认参数
int fun(int a = 1,int b){}
这里的形参a为函数的默认参数,如果在调用时只传一个实参,则默认a为1.
类的三大基石:继承,封装,多态 ! ! !
关于派生类的访问权限:
继承分为:私有继承,共有继承,保护继承:
我们几乎不使用 protected 或 private 继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:
1,公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。,
2,保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
3,私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
代码演示:
# include<iostream>
# include<string>
/*基类*/
class people
{
public:
int A;
void init(int a,int b,int c) //成员函数
{
A = a;
B = b;
C = c; //基类内部成员函数可以访问所有类成员
}
private:
int B;
protected:
int C;
};
/*公有派生类*/
class p1:public people
{
public:
int A1;
void init(int a1,int b1,int c1)
{
A = a1;
//B = b1; //报错,公有类型派生类不能访问基类私有成员
C = c1;
}
private:
int B1;
protected:
int C1;
};
/*私有派生类*/
class p2:private people
{
public:
int A2;
void init(int a2,int b2,int c2)
{
A = a2;
//B = b2; //报错,私有类型派生类不能访问基类私有成员
C = c2;
}
private:
int B2;
protected:
int C2;
};
/*保护派生类*/
class p3:protected people
{
public:
int A3;
void init(int a3,int b3,int c3)
{
A = a3;
//B = b3; /报错,保护类型派生类不能访问基类私有成员
C = c3;
}
private:
int B3;
protected:
int C3;
};
int main()
{
people yu;
yu.init(1,2,3);
yu.A; //基类对象仅能访问基类的公有成员
//yu.B; //报错
//yu.C; //报错
p1 yu1;
yu1.init(1,2,3);
yu1.A;
//yu1.B; //报错
//yu1.C; //报错,公有继承方式派生类对象仅能访问基类公有成员
p2 yu2;
yu2.init(1,2,3);
//yu2.A; //报错
//yu2.B; //报错
//yu2.C; //报错,私有继承方式派生类对象不能访问基类任何成员
p3 yu3;
yu3.init(1,2,3);
//yu3.A; //报错
//yu3.B; //报错
//yu3.C; //报错,保护继承方式派生类对象不能访问基类任何成员
getchar();
return 0;
}
我们可以根据访问权限总结出不同的访问类型,如下所示:
访问 (父类) public protected private
同一个类 yes yes yes
公有派生类 yes yes no
公有派生类对象 yes no no
(下面两个的各个权限是一样的)
私有派生类 yes yes no
私有派生类对象 no no no
保护派生类 yes yes no
保护派生类对象 no no no
可总结为两点:
1,无论以何种类型继承基类,派生类都不能访问基类的私有成员(变量,函数),只能访问保护和公有。
2,有,且只有,继承类型为公有,的派生类,的对象。才能,且只能,访问基类的公有成员。
间接访问类私有成员的方式:在类内部公有成员函数里,将私有成员返回。通过在外部调用公有成员函数,便可以实现间接访问类私有成员。
多继承:
多继承即一个子类可以有多个父类,它继承了多个父类的特性。
C++ 类可以从多个类继承成员,语法如下:
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};
重载函数:
用途:
在一个类中可以定义多个构造函数,以便提供不同的初始化的方法,供用户选用。
特点:
1,这些构造函数具有相同的名字,
2,参数的个数或参数的类型,必须至少有一个不相同不相同。
3,返回类型,形参标识符不同,并不能构成函数重载合法的依据。
通过下面的例子可以了解怎样应用构造函数的重载:
#include <iostream>
using namespace std;
class printData
{
public:
void print(int i) {
cout << "Printing int: " << i << endl;
}
void print(double f) {
cout << "Printing float: " << f << endl;
}
void print(char* c) {
cout << "Printing character: " << c << endl;
}
};
int main(void)
{
printData pd;
pd.print(5);
pd.print(500.263);
pd.print("Hello C++");
return 0;
}
/*打印结果*/
/*
*Printing int: 5
*Printing float: 500.263)
*Printing character: c
*/
关于构造函数的重载的几点说明:
1,调用构造函数时不必给出实参的构造函数,称为默认构造函数(default constructor)。显然,无参的构造函数属于默认构造函数。一个类只能有一个默认构造函数。
2,如果在建立对象时选用的是无参构造函数,应注意正确书写定义对象的语句。
3,尽管在一个类中可以包含多个构造函数,但是对于每一个对象来说,建立对象时只执行其中一个构造函数,并非每个构造函数都被执行。
在C++里面小数默认为double,而不是float。也就是说想要传入小数实参时, 对应的形参类型必须为double,如果用float编译不通过。
为什么要调用父类的构造函数?
构造函数用来初始化类的对象,与父类的其它成员不同,它不能被子类继承(子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法)。因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法。
C++构造函数调用顺序:
1、创建派生类的对象,基类的构造函数优先被调用(也优先于派生类里的成员类);
2、如果类里面有成员类,成员类的构造函数优先被调用;
3、派生类如果有多个基类,则构造函数的调用顺序是某类在–类派生表–中出现的
顺序而不是它们在成员初始化表中的顺序;
4、成员类对象构造函数如果有多个成员类对象则构造函数的调用顺序是对象在类中
被声明的顺序而不是它们出现在成员初始化表中的顺序;
5、派生类构造函数
作为一般规则派生类构造函数应该不能直接向一个基类数据成员赋值而是把值传递
给适当的基类构造函数,否则两个类的实现变成紧耦合的(tightly coupled)将更加难于
正确地修改或扩展基类的实现。(基类设计者的责任是提供一组适当的基类构造函数)
代码演示多继承派生类调用父类构造函数的执行顺序:
#include<iostream>
#include<string>
using namespace std;
/*基类1*/
class Base1
{
private:
int a;
public:
Base1(int x) //基类Base1的构造函数
{
a=x;
cout<<"Base1 Constructor !"<<endl;
}
int geta() {return a;}
};
/*基类2*/
class Base2
{
private:
int b;
public:
Base2(int x) //基类Base2的构造函数
{
b=x;
cout<<"Base2 Constructor !"<<endl;
}
int getb() {return b;}
};
/*多继承共有类型派生类*/
class Derived : public Base1,public Base2 //类派生表,此处的继承顺序决定,基类构造函数调用
{
private:
int c;
public:
Derived(int x,int y, int z) : Base2(z),Base1(y)
//成员初始化表,通过传值调用基类函数实现基类成员变量的初始化
{
c=x;
cout<<"Derived Constructor!"<<endl;
}
void show()
{
cout<<geta()<<' '<<getb()<<' '<<c<<endl;
}
};
/*主函数*/
void main()
{
Derived obj (1,2,3); //派生类创建对象并初始化成员变量,这三个实参只有一个是给自己用。
obj.show ();
getchar();
}
/*
程序的输出结果:
Base1 Constructor !
Base2 Constructor !
Derived Constructor!
2 3 1
*/
代码说明:
1,声明一个子类的对象时,首先调用父类的构造函数,
2,如果一个子类有多个父类时,则按照声明的顺序依次执行父类的构造函数,如class Derived : public Base1,public Base2 你先声明Base1,后声明Base2,所以先调用Base1后调用Base2的构造函数,而与 Base2(z),Base1(y)的顺序无关。