c++基础 五

继承

与kotlin中一样,类的继承使用 : 表示。
不同的是,c++继承分为私有继承、公开继承,默认为私有继承

  • 1.默认是 隐式代码: : private Person
  • 2.私有继承:在子类里面是可以访问父类的成员,但是在类的外面不行
  • 3.必须公开继承,才可以访问父类的成员
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Father {

private:
int age;
public:
char * name;
};

class Son : Father { // 默认私有 private 继承
public:
void setName() {
// this->age = 19;// 'age' is a private member of 'Father'
this->name = "son";
}
char * getName(){
return this->name;
}
};
class Daugther : public Father { // 公开继承
public:
void setName() {
// this->age = 19; // 'age' is a private member of 'Father'
this->name = "dauther";
}
char * getName(){
return this->name;
}
};


int main(){
cout << "HELLO WORLD!" << endl;

Son son;
son.setName();
// son.name; //报错 'name' is a private member of 'Father'
Daugther daugther;
daugther.setName();
cout << "daugther.name : " << daugther.name << endl;
return 0;
}

总结:

  • 子类不能访问父类的私有属性
  • 子类直接继承为私有继承
  • 私有继承的子类对象不能访问父类的属性,只能在类中访问
  • 公开继承的子类对象可以访问父类的属性,在类中同样可以

多继承

  • C++ 是允许多继承的
  • Java语言不允许多继承,多继承有歧义,如果Java语言多继承 就会导致代码不健壮,(二义性)
  • Java多实现:做的非常棒,严格避免出现 二义性问题(歧义)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Mother{
public:
void raisChild() {
cout << "Mother raisChild" << endl;
}
void work() {
cout << "Mother work" << endl;
}
void play() {
cout << "Mother play" << endl;
}
void playWithChild() {
cout << "Mother playWithChild" << endl;
}

};

class Father {
public:
void smoking() {
cout << "Father smoking" << endl;
}
void work() {
cout << "Father work" << endl;
}
void play() {
cout << "Father play" << endl;
}
void playWithChild() {
cout << "Father playWithChild" << endl;
}
};

class Son: public Mother, public Father {
public:
void work() {
cout << "Son work" << endl;
}
void play() {
cout << "Father play" << endl;
}
};


int main() {
cout << "HELLO WORLD!" << endl;
Son son;
// 这个是优先寻找子类的函数,因为特别明确,没有问题,还没有产生歧义(二义性)
son.work();
son.play();
son.raisChild();
son.playWithChild(); // 报错 Member 'playWithChild' found in multiple base classes of different types
return 0;
}

如上述代码所示,Son类同时继承自Father、Mother类,这两个类有一些相同的函数work、play、playWithChild
但子类Son也实现了work、play时,执行这些函数不会报错,
但调用playWithChild则会报错,因为两个父类都有该函数、但子类未实现,此时就存在二义性问题。
解决这样的问题,存在两个办法:

  • 1、指定调用哪个父类的该函数 使用 ::父类.函数名
    son.Father::playWithChild();
  • 2、在子类也实现该函数
    在Son类中添加playWithChild函数。

总结:

  • 1、c++可以多继承
  • 2、多继承时,如果多个父类间存在同名同参函数,子类指针使用时,会存在二义性问题,需要子类也实现该函数,或者指定父类调用
  • 3、真实开发时,一般时子类也会定义同名成员,覆盖掉多个父类同名成员。

虚继承

二义性问题出现在菱形继承。
关于二义性问题,还有一种解决办法,就是虚继承。
第三种解决方案: 【虚基类】 属于 虚继承的范畴
真实C++开始,是很少出现,二义性(歧义) 如果出现, 系统源码(系统用 第三种解决方案)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 祖父类
class Object{
public:
int number;
void show() {
cout << "Object show run..." << endl;
}
};

// 等下讲 virtual 的原理是什么 ...

// 父类1
class BaseActivity1 : virtual public Object {
// public:int number; // 人为制作二义性 error: request for member 'number' is ambiguous
};

// 父类2
class BaseActivity2 : virtual public Object {
// public:int number;
};

// 子类
class Son : public BaseActivity1, public BaseActivity2 {

};

int main() {
cout << "HELLO WORLD!!!!" << endl;

Object object;
BaseActivity1 baseActivity1;
BaseActivity2 baseActivity2;
Son son;

object.number = 100;
baseActivity1.number = 200;
baseActivity2.number = 300;
son.number = 400;

object.show();
baseActivity1.show();
baseActivity2.show();
son.show();

cout << object.number << endl;
cout << baseActivity1.number << endl;
cout << baseActivity2.number << endl;
cout << son.number << endl;

return 0;
}

虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class)

上面的例子中:Object就是虚基类,BaseActivity1、BaseActivity2都是虚继承于Object,然后Son都公开继承于BaseActivity1、BaseActivity2
在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。

虚函数

多态(虚函数)。 动态多态(程序的角度上:程序在运行期间才能确定调用哪个类的函数 == 动态多态的范畴)
Java语言默认支持多态
C++默认关闭多态,怎么开启多态? 虚函数 在父类上给函数增加 virtual关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class BaseActivity {

public:
virtual void onStart(){
cout << "BaseActivity onStart" << endl;
}
};

class HomeActivity : public BaseActivity {

public:
void onStart() {
cout << "HomeActivity onStart" << endl;
}
};

class MyActivity : public BaseActivity {
public:
void onStart() {
cout << "MyActivity onStart" << endl;
}
};

void onActivityStart(BaseActivity * baseActivity) {
baseActivity->onStart();
}


int main() {
cout << "HELLO WORLD!!" << endl;
HomeActivity * homeActivity = new HomeActivity();
MyActivity * myActivity = new MyActivity();

onActivityStart(homeActivity);
onActivityStart(myActivity);

if(myActivity && homeActivity) {
delete homeActivity;
homeActivity = NULL;
delete myActivity;
myActivity = NULL;
}
return 0;
}
  • 多态的定义 *
    父类的引用指向之类的对象,同一个方法有不同的实现,重写(动态多态)和 重载(静态多态)

函数重载

函数重载即为 静态多态
重载:函数名相同,但入参不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int add (int a, int b) {
cout << "int: " << a + b << endl;
return a + b;
}

float add (float a, float b) {
cout << "float: " << a + b << endl;
return a + b;
}

double add (double a, double b) {
cout << "double: " << a + b << endl;
return a + b;
}

int main() {
cout << "HELLO WORLD!!" << endl;
add(1, 2);
add(1.3f, 4.5f);
add(1.45, 1.67);
return 0;
}

纯虚函数

c++纯虚函数类似于java中的抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class BaseActivity {

private:
void setContentView(int layoutId){
cout << "XmlResourceParser解析布局文件信息... 反射" << endl;
}

public:
void onCreate(){
setContentView(getLayoutId());
initData();
initView();
}
// virtual int getLayoutId(); // 虚函数
virtual int getLayoutId() = 0; // 纯虚函数
virtual void initData() = 0;
virtual void initView() = 0;
};

class HomeActivity : public BaseActivity {
public:
int getLayoutId() {
return 100;
}
void initData() {
cout << "HomeActivity initData" << endl;
}
void initView(){
cout << "HomeActivity initView" << endl;
}
};



int main() {
cout << "Hello world!" << endl;
// 错误:抽象类型 BaseActivity 绝对不能实例化
// BaseActivity ba; // 報錯 Variable type 'BaseActivity' is an abstract class
HomeActivity home;
home.onCreate();

return 0;
}

注意纯虚函数记得在函数后面写 = 0
如果不写 = 0 则会运行报错

全纯虚函数

如果类中的函数都是虚函数,则这个类可以被成为全纯虚函数, 相当于java中的接口

回调

与java中的函数回调类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class User {

public:
int id;
string name;
string mobile;

User(int id, string name, string mobile): id(id), name(name), mobile(mobile){
this -> toString();
}

void toString(){
cout << "用户名:" << this->name << " 用户id:" << this->id << " 用户手机号:" << this->mobile << endl;
}
};

class ILognResult {
public:
virtual void success(int code, User user) = 0;

virtual void fail(int code, string message) = 0;
};




void loginAction(string userName, string password, ILognResult & loginResult) {
if(userName.empty() || password.empty()) {
cout<< "登录的账号与用户名都不能为空" << endl;
return;
}
if("justin" == userName && "123321qQ" == password) {
loginResult.success(200, User(1121, "justin", "13163396276"));
} else {
loginResult.fail(404, "用户名或密码错误");
}
}

class LoginResultImpl : public ILognResult {
public:
void success(int code, User user){
cout << "登录成功:userName:" << user.name << " mobile: " << user.mobile << endl;
}

void fail(int code, string message) {
cout << "登录失败:错误状态码:" << code << " 错误信息: " << message << endl;
}
};


int main(){
cout << "HELLO WORLD!" << endl;
string userName;
cout << "请输入用户名" << endl;
cin >> userName;
string password;
cout << "请输入密码" << endl;
cin >> password;
LoginResultImpl loginResult;
loginAction(userName, password, loginResult);

return 0;
}

如上代码就是一个登录操作的回调 其实是非常类似于 java中的接口回调的

模版函数

c++ 中没有范型概念,但是有模版函数,与java中的范型类似

像我们在之前的 静态多态中对于重载时的举例,加法
当我们针对不同的数据类型都需要进行一次重载,但当我们使用函数模版时,写一次即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template <typename  T>
T add(T a, T b) {
cout << "result:" << a + b << endl;
return a + b;
}

int main(){
cout << "HELLO WORLD!" << endl;
int a = add(1, 3);
float f = add(1.4f, 66.8f);
double d = add(3.6, 88.99);

cout << "a:" << a << endl;
cout << "f:" << f << endl;
cout << "d:" << d << endl;

return 0;
}

如上所示,使用模版函数完成了各个类型的加法计算,使用也与java中的范型及其类似