avatar

C++初步涉及

C++ 函数

友元

一般情况下,类私有变量是无法直接访问的,但是定义友元就可以在外部函数直接访问私有变量,测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
class newClass{
private:
int private_val = 1;
public:
friend int test(newClass nc);
void check(){
printf("%d\n",private_val);
}
};
int test(newClass nc){
return nc.private_val;
}
int main(){
newClass nc;
nc.check();
printf("private_val:%d\n",test(nc));
return 0;
}

输出结果如下

1
2
1
private_val:1

使用友元类时注意:

(1) 友元关系不能被继承。

(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。

(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明

设置函数默认值


1
2
3
4
5
6
7
8
9
#include <iostream>
using namespace std;
void function_name(unsigned long long val = 0xdeadbeef){
printf("%lu",val);
}
int main(){
function_name();
return 0;
}

输出结果如下

1
3735928559

总结:

所以只需要在参数在定义处直接赋值即可设置初始值

C++ 多态


C++类的定义如下

1
2
3
4
5
6
7
8
9
10
11
12
13
class class_name{
private:
int val1_name = 0;
void function1(){

}

pubilc:
int val2_name = 0;
void function2(){

}
};

C++派生类定义

无构造函数的情况

首先我们先要有一个基类,我预先定义为class_base,然后我们利用这个基类定义一个派生类

1
2
3
4
5
6
7
8
9
10
11
12
13
class new_class:public class_base(){
private:
int val1_name = 0;
void function1(){

}

pubilc:
int val2_name = 0;
void function2(){

}
};

这样派生出来的类,外部调用的时候可以调用基类未被重写的公开函数。同时为了保证封装性,派生类也无法直接使用基类私有函数。

存在构造函数的情况

定义类名为class_base的基类,然后同时定义好构造函数。注意构造函数最好是public的形式

1
2
3
4
5
6
7
8
class new_class:public class_base{
private:

public:
new_class(args):class_base(args){

}
};

虚函数


如果我们想使用多态,肯定必须要了解虚函数

虚函数可以让我们重名函数指向我们想要执行的函数,其原理是通过虚函数表(Virtual Table)来实现的。它类似于一个地图,指明了实际所应该调用的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
class person{
public:
virtual void test1(){
puts("I am person's test1!");
}
};
class child:public person{
public:
virtual void test1(){
puts("I am child's test1!");
}
};
int main(){
child c;
person* a = &c;
a->test1();
c.test1();
return 0;
}

输出结果如下

1
2
I am child's test1!
I am child's test1!

当我把main改成以下代码时

1
2
3
4
5
6
7
int main(){
child c;
person a = c;
a.test1();
c.test1();
return 0;
}

输出结果如下

1
2
I am person's test1!
I am child's test1!

解释:

如果我们使用的是传址的形式,则调用的时候依旧会调用等号右边的类的函数,因为等号右边的类所对应的vtable已经被覆盖为等号右边的函数了。

如果我们使用的是赋值的形式,则调用的时候只是把变量进行了复制,而函数指针(vtable)没有被改动,所以按照被赋值变量的类进行调用函数

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
class person{
public:
void test1(){
puts("I am person's test1!");
}
};
class child:public person{
public:
virtual void test1(){
puts("I am child's test1!");
}
};
int main(){
child c;
person * a = &c;
a->test1();
a->test2();
c.test1();
return 0;
}

输出结果如下

1
2
3
I am person's test1!
I am person's test2!
I am child's test1!

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
class person{
public:
void test1(){
puts("I am person's test1!");
}
};
class child:public person{
public:
virtual void test1(){
puts("I am child's test1!");
}
};
int main(){
child c;
person * a = &c;
a->test1();
a->test2();
c.test1();
return 0;
}

输出结果如下

1
2
3
I am person's test1!
I am child's test2!
I am child's test1!

解释:

由于没有给基类的函数标记为virtual,所以当我们赋值之后调用重写的虚函数并不会调用派生类的函数,而是会调用基类的函数,但是标记了virtual的函数依旧会被重写。可见想要多态,基类用虚函数是少不了了,需要

纯虚函数


其实就是一个接口

纯虚函数需要在定义的结尾加一个=0,格式如下

1
virtual void function_name()=0;

如果基类中使用了纯虚函数,则派生类必须声明function_name()函数,不然编译器就会报错。

知识小补充

构造函数不可以被定义为虚函数

文章作者: 咲夜南梦
文章链接: http://yoursite.com/2020/01/13/C++%E5%88%9D%E6%AD%A5%E6%B6%89%E5%8F%8A/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 咲夜南梦's 博客
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论