C++杂记

  • 操作符重载:

情景1,通常情况下,我们将2个数据类型为结构体类型的2个数相加时,所书写的函数。

代码1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;
struct Complex
{
float real;
float image;
};
Complex add(Complex a,Complex b)
{
Complex c;
c.image = a.image + b.image;
c.real = a.real + b.real;
return c;
}
int main()
{
Complex aa,bb,cc;
aa = {1,1};
bb = {2,2};
cc = add(aa,bb);
cout<<"cc.image = "<<cc.image<<endl;
cout<<"cc.real = "<<cc.real<<endl;
return 0;
}

运行结果:

1
2
cc.image = 3
cc.real = 3

情景2,我们可以通过使用操作符重载技术,来实现,像这种结构体类型的数据,可以按照普通的数据类型(char,int ,double……)进行操作。

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
#include <iostream>
using namespace std;
struct Complex
{
float real;
float image;
};
Complex operator+(Complex a,Complex b)
{
Complex c;
c.real = a.real + b.real;
c.image = a.image + b.image;

return c;
}
int main()
{
Complex aa,bb,cc;
aa = {1,1};
bb = {2,2};
cc = aa+bb;
cout<<"cc.real = "<<cc.real<<endl;
cout<<"cc.image = "<<cc.image<<endl;
return 0;
}

运行结果:

1
2
cc.real = 3
cc.image = 3
  • 功能:设置一个简易的电子时钟,可以显示时分秒
  • 技巧:setfill函数,在给定的输出域宽内填充字符; setw函数,设置域宽为n个字符

源码:

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
#include <iostream>
#include <iomanip>
#include <windows.h>
#include <unistd.h>
using namespace std;

int main()
{
int hour = 0,min = 0,sec = 0;
while(1)
{
sec++;
sleep(1);
if(sec>=60)
{
sec = 0;
min++;
if(min>=60)
{
min = 0;
hour++;
if(hour >= 24)
{
hour = 0;
}
}
}
cout<<setfill('0')<<setw(2)<<hour<<":"<<setw(2)<<min<<":"<<setw(2)<<sec<<endl;
}
return 0;
}

总结:

setfill函数和setw函数,这2个函数结合起来使用,用来制作一个简易的电子时钟还是蛮不错的。

  • 函数重载:

代码1:

特征:函数重载反映在,函数的返回值和函数的返回参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;
float abs(float f);
int abs(int i);
int main()
{

float ret_f = abs(-5.5f);
cout<<ret_f<<endl;

int ret_i = abs(-5);
cout<<ret_i<<endl;
return 0;
}

float abs(float f)
{
return ((f>0)?(f):(-f));
}
int abs(int i)
{
return ((i>0)?(i):(-i));
}

运行结果:

1
2
3
5.5

5

代码2:

特征:函数重载反映在,函数的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

using namespace std;
void abs(int i);
void abs(double d);
int main()
{
abs((double)4);
return 0;
}
void abs(int i)
{
cout<<"int abs(i)"<<endl;
}
void abs(double d)
{
cout<<"double abs(d)"<<endl;
}

运行结果:

1
double abs(d)
  • 默认参数:

    代码实战1,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <time.h>
using namespace std;
int volume(int l,int w,int h=6)
{
return l*w*h;
}
void weatherCast(string w = "pm 2.5")
{
time_t t = time(0);
char tmp[64];
strftime(tmp,sizeof(tmp),"%Y-%m-%d %X %An",localtime(&t));
cout<<tmp<<"today's weather "<<w<<endl;
}
int main()
{
cout<<"volume = "<<volume(1,1)<<endl;
weatherCast("pm = 555");
return 0;
}

运行结果:

1
2
3
volume = 6
2018-11-08 16:36:18 Thursday
today's weather pm = 555

总结:

默认参数,当我们不给它任何的参数时,它就按照形参中实现指定的值。

当,我们想要设定特定的参数时,那就直接给它传入相应的值即可。

代码实战2,

默认参数的存在,的确在一定程度上给我们提供了不少的便利性。然而,它也有它的囧态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;
int abs(int a)
{
cout<<"int abs(int a)"<<endl;
}
int abs(int a,int b=5)
{
cout<<"int abs(int a,int b=5)"<<endl;
}
int main()
{
abs(1,5);//假如写成:abs(1),此时报错。
return 0;
}

总结,

​ 当我们写为abs(1),里面仅有一个参数时,函数会陷入两难的境地,它不知道要执行abs(int a)还是要执行

abs(int a,int b=5)。

  • 引用:

引用的定义:引用的意义,是为了给一个已有的变量名起一个别名。

代码实战1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;
int main()
{
int a;
int &b = a;
int *p;
int *&pp = p;

cout<<"&a = "<<&a<<endl;
cout<<"&b = "<<&b<<endl;
cout<<"p = "<<p<<endl;
cout<<"pp = "<<pp<<endl;
return 0;
}

运行结果:

1
2
3
4
&a = 0x28fea4
&b = 0x28fea4
p = 0x68
pp = 0x68
  • 在C语言中,打印一个数字。分别使用十进制、十六进制、八进制的形式打印。

代码如下:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{

int a = 128;
printf("dec: a = %dn",a);
printf("hex: a = %xn",a);
printf("oct: a = %on",a);
return 0;
}

运行结果:

1
2
3
dec: a = 128
hex: a = 80
oct: a = 200

在C++中,打印一个数字。分别使用十进制、十六进制、八进制的形式打印。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <stdlib.h>
#include <iomanip>
using namespace std;

int main()
{
int a = 1234;
cout<<dec<<a<<endl;
cout<<setbase(10)<<a<<endl;
cout<<"0x"<<hex<<a<<endl;
cout<<"0x"<<setbase(16)<<a<<endl;
cout<<oct<<a<<endl;
cout<<setbase(8)<<a<<endl;
}

运行结果:

1
2
3
4
5
6
1234
1234
0x4d2
0x4d2
2322
2322

总结,dec等价于setbase(10);hex等价于setbase(16);oct等价于setbase(8)。

  • const关键字与引用之间的暧昧。
1
2
3
4
5
6
7
8
情景1:
const int a = 1234;
int &b = a;
该使用方法是错误的。
情景2:
int a = 1234;
const int &b = a;
该使用方法是OK,正确的。
  • 熟悉new和delete的使用。

情景1:

1
2
3
4
int *p = new int(123);
cout<<*p<<endl;
运行结果:
123

情景2:

1
2
3
4
5
6
7
8
9
10
11
12
char *p = new char [10];
strcpy(p,"hello world");
cout<<p<<endl;
运行结果:
hello world

string *str = new string("china");
cout<<str<<endl;
cout<<*str<<endl;
运行结果:
0x3c1518
china
  • C++中4种强制类型转化。

    tatic_cast reinterpret_cast const_cast dynamic_cast,其中dynamic_cast在后面学习的多态中,会详细来讲今天,暂且不提。

static_cast

它用来解决全双隐问题和半双隐问题。

全双隐问题(a.b两种数据类型的变量,a既可以赋值给b,b又可以赋值给a)

半双隐问题(a,b两种类型的变量,a可以赋值给b,b不可以赋值给a;或者…..)

下面先看一下static_cast使用在什么地方呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1. 全双隐问题:
int a;
float b;
a = b;
b = a; 首先,上面这4行代码是正确的。在这种情形之下,恰好也就是static_cast的用武之地了。
如下,
int a = 123;
float b = 1.23;
a = static_cast<float>(b);
b = static_cast<int>(a);
cout<<a<<"t"<<b<<endl;
运行结果:
1 1

2. 半双隐问题:
int *p;
void *q;
q = p;//这样写是正确的。但是,p = q,这样写的话,就是错误的。
p = static_cast<int *>(q); // 这样写也是正确的。

reinterpret_cast

它是用来解决,2个方向都是不可以转换的。

1
2
3
4
5
6
7
char *p;
int *q;
此时,无论是p = q;还是q = p都是不正确的。
然而,
p = reinterpret_cast<char *>(q);
q = reinterpret_cast<int *>(p);
这2种情况都是正确的。

const_cast

它是用来脱常的。(正常情况下,引用是只可以对变量进行取引用的。但是,有了const的介入,就导致了引用,它不止可以对变量取引用。而且它还可以对常量或者表达式取引用。)

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
情景1,
谈一谈const的妙用之处。通常情况下,引用只可以对一个变量,进行取引用操作。而,自从有了const关键字之后,它,所实现的功能:取引用,即可以对常量取引用;也可以对表达式进行取引用操作。
void func_1(int &a)
{

}
main:
int a = 3;
func_1(a);
以上代码是完全没有毛病的。这也是引用的一般、正常的使用方法。
void func_2(const int &a)
{

}
main:
int a = 3;
func_1(3);
func_1(a+3); //这2个调用,在没使用const之前都是行不通的。但是,在这里都是OK的。
情景2,
正式来讲一下const_cast是如何使用的。
void func(int &a)
{

}
main:
const int a = 3;
func(a); //此时,这样调用函数,一定是错误的。
func(const_cast<int &>(a)); //把原本为const类型的变量,给,成功的"脱常"。
情景3,
const int a = 12;
int &ra = a; //此时,编译报错。
使用const_cast即可解决上述问题。
int &ra = const_cast<int &>(a);
情景4,
const int a = 10;
int *p = const_cast<int *>(&a);
*p = 30;
cout<<"*p = "<<*p<<"t"<<"a = "<<a<<endl;
注意:
const_cast一般只用于引用和指针,是不可以用于变量的。具体,const_cast<int &> const_cast<int *>...
  • C++中命名空间的引入。

定义:命名空间是对全局区域的再次划分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
情景1,
int val = 200;
main:
int val = 100;
cout<<"::val = "<<::val<<endl;
cout<<"val = "<<val<<endl;
运行结果:
::val = 200
val = 100
情景2,
namespace my_space
{
int x=5,y=5;
namespace others
{
int m = 6,n = 6;
}
}
main:
using namespace my_space::others;
cout<<"m = "<<m<<"t"<<"n = "<<n<<endl;
运行结果:
m = 6 n = 6

类与对象:

  • 构造器、析构器、使用初始化列表来初始化参数。

构造器:在类对象创建时,自动调用。

析造器:在对象销毁时,自动调用。

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
class Line
{
public:
void setLength(double len);
double getLength(void);
Line();
~Line();
private:
double length;
};
//构造器
Line::Line(void)
{
cout<<"Object is being created"<<endl;
}
//析造器
Line::~Line(void)
{
cout<<"Object is being deleted"<<endl;
}
void Line::setLength(double len)
{
length = len;
}
double Line::getLength()
{
return length;
}
main:
Line line;
line.setLength(6.66);
cout<<"length of line :"<<line.getLength()<<endl;
运行结果:
Object is being created
length of line :6.66
Object is being deleted

使用初始化列表来初始化参数。

​ 注意它使用的场景,适用于构造器身上。

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
情景1,
class Line
{
public:
void setLength(double len);
double getLength(void);
Line(double len);
~Line();
private:
double length;
};
//使用初始化列表,来初始化参数。
Line::Line(double len)
:length(len)
{
cout<<"Object is being created,length = "<<len<<endl;
}
Line::~Line(void)
{
cout<<"Object is being deleted"<<endl;
}
main:
Line line(1.23); //注意这里的对象,在初始化时,方式和前面是不一样的。
运行结果:
Object is being created,length = 1.23
Object is being deleted
情景2,
class A
{
public:
A(char *ps)
:len(strlen(name.c_str())),name(ps){} //c_str()将string类型转化为char *类型的
void dis()
{
cout<<len<<endl;
}
private:
string name;
int len;
};
main:
A a("a");
a.dis();
注意:
使用初始化列表初始化参数时,一定要注意,初始化的先后顺序。
  • 拷贝构造:
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< 大专栏  C++杂记/span>
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
拷贝构造的格式:
class 类名
{
类名(const 类名 &another)
拷贝构造体
}
情景1,浅拷贝。(默认的)
class A
{
public:
A(int d,char *p)
:data(d)
{
pd = new char[strlen(p)+1];
strcpy(pd,p);
}
~A()
{
delete []pd;
}
#if 0
// 这是深拷贝时,自己手动创建的拷贝构造器。
A(const A &another)
{
pd = new char[strlen(another.pd)+1];
strcpy(pd,another.pd);
}
#endif
void dis()
{
cout<<data<<"t"<<pd<<endl;
}
private:
int data;
char *pd;
};
main:
A a(1,"a");
a.dis();
A b(a);
b.dis();
运行结果:
1 a
1 a
情景2,深拷贝。(需要自己提供)
见情景1,中的代码。加上,"#if 0...#endif"自己手动添加的拷贝构造器,之后,运行结果如下。
1 a
104 a
情景3,深拷贝。
class A
{
public:
A(int d,char *p)
:data(d)
{
pd = new char[strlen(p)+1];
strcpy(pd,p);
}
~A()
{
delete []pd;
}
A(const A& another)
{
pd = new char[strlen(another.pd)+1];
strcpy(pd,another.pd);
}
void dis()
{
cout<<data<<"t"<<pd<<endl;
}
private:
int data;
char *pd;
};
main:
A a(123,"abc");
A b = a;
a.dis();
b.dis();
运行结果:
123 abc
104 abc
  • this指针。

定义:系统在创建对象时,默认生成指向当前对象的指针。

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
class Stu
{
public:
Stu(string name,int age)
{
this->name = name;
this->age = age;
}
Stu &growUp()
{
this->age++;
return *this;
}
void display()
{
cout<<name<<"--"<<age<<endl;
}
private:
string name;
int age;
};
main:
Stu s("lbc",25);
s.display();
s.growUp();
s.display();
运行结果:
lbc--25
lbc--26
  • 构造器、拷贝构造、赋值运算符重载,这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
42
43
44
45
46
47
48
49
50
51
52
53
54
class my_str
{
public:
my_str(){}
//构造器,带参数的
my_str(int _id,char *_name)
{
cout<<"constructor"<<endl;
id = _id;
name = new char[strlen(_name)+1];
strcpy(name,_name);
}
//拷贝构造
my_str(const my_str &str)
{
cout<<"copy constructor"<<endl;
id = _id;
name = new char[strlen(str.name)+1];
strcpy(name,str.name);
}
//赋值运算符重载
my_str &operator=(const my_str &str)
{
cout<<"operator = "<<endl;
if(this != &str)
{
this->id = str.id;
int len = strlen(str.name);
name = new char[len+1];
strcpy(name,str.name);
}
return *this;
}
~my_str()
{
delete name;
}
private:
char *name;
int id;
};
main:
my_str str1(123,"abc");
cout<<"------------------"<<endl;
my_str str2;
str2 = str1; //这里是,赋值运算符重载
cout<<"------------------"<<endl;
my_str str3 = str2; //这里是,拷贝构造
运行结果:
constructor
------------------
operator =
------------------
copy constructor

注意: 深拷贝也可以称之为拷贝构造。

  • const关键字构成的函数重载。
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
class A
{
public:
A():x(12),y(34){}
void dis()
{
cout<<"void dis()"<<endl;
cout<<x<<"t"<<y<<endl;
}
void dis() const
{
cout<<"void dis() const"<<endl;
cout<<x<<"t"<<y<<endl;
}
private:
int x,y;
};
main:
A a;
a.dis();
运行结果:
void dis()
12 34
总结:
const关键字修饰函数时,是可以构成函数重载的。此时,优先执行,非const修饰的函数。
  • static关键字在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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
情景1,
点1:static修饰的类成员,不需要类对象,也是可以对其成员进行访问的。
点2:要想使用static类型的成员,必须先要对其初始化。而且,这个初始化的过程还必须在类外,进行初始化
class School
{
public:
static void add_lib_book(string book)
{
lib = lib + book;
}
public:
string tower;
string lake;
static string lib;
};
string School::lib = "jx lib";
main:
School::lib = "jx lib";
cout<<School::lib<<endl;
School::add_lib_book(" good book");
cout<<School::lib<<endl;
运行结果:
jx lib
jx lib good book

情景2,
static函数存在的意义在于,用来管理类中的静态成员变量。
class Student
{
public:
Student(int n,int a,float s)
:num(n),age(a),score(s){}
static float average();
void total()
{
count++;
sum = sum + score;
}
private:
int num;
int age;
float score;
static float sum;
static int count;
};

float Student::sum = 0;
int Student::count = 0;
float Student::average()
{
return sum/count;
}
main:
Student stu[3] = {
Student(100,10,1),
Student(200,20,2),
Student(300,30,3)
};
for(int i=0;i<3;i++)
{
stu[i].total();
cout<<Student::average()<<endl;
}
运行结果:
1
1.5
2
  • this指针
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
实战1,this指向普通函数
void dis(int cnt)
{
cout<<"cnt = " <<cnt<<endl;
}
main:
void (*pf)(int) = dis;
pf(10)
运行结果:
cnt = 10
实战2,this指向类成员函数
class Student
{
public:
Student(string n,int a)
:name(n),age(a){}
void dis()
{
cout<<"name: "<<name<<"t"<<"age: "<<age<<endl;
}
string name;
int age;
};
main:
Student s("lbc",120);
void (Student::*pf)() = Student::dis;//这里要注意,函数指针书写的格式。
(s.*pf)();
运行结果:
name: lbc age: 120
  • 友元函数friend
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
64
65
66
67
68
69
70
71
72
73
74
情景1,
class Point
{
public:
Point(float xx,float yy)
:x(xx),y(yy){}
void get_point();
friend float cal_distance(Point &a,Point &b);
private:
float x,y;
};
void Point::get_point()
{
cout<<"("<<x<<","<<y<<")"<<endl;
}
float cal_distance(Point &a,Point &b)
{
float d_x = a.x - b.x;
float d_y = a.y - b.y;
return sqrt(d_x*d_x - d_y*d_y);
}
main:
Point p1(1.1,2.2);
Point p2(2.2,2.2);
p1.get_point();
p2.get_point();
float res = cal_distance(p1,p2);
cout<<"res = "<<res<<endl;
运行结果:
(1.1,2.2)
(2.2,2.2)
res = 1.1
情景2,
class Point;
class Cal_distance
{
public:
float distance(Point &a,Point &b);
};
class Point
{
public:
Point(float xx,float yy)
:x(xx),y(yy){}
void get_point();
friend float Cal_distance::distance(Point &a,Point &b);
private:
float x;
float y;
};
void Point::get_point()
{
cout<<"("<<x<<","<<y<<")"<<endl;
}
float Cal_distance::distance(Point &a,Point &b)
{
float d_x = a.x - b.x;
float d_y = a.y - b.y;
return sqrt(d_x*d_x + d_y*d_y);
}
main:
Point p1(1.1,2.2);
Point p2(1.1,3.3);
p1.get_point();
p2.get_point();
Cal_distance cd;
float res = cd.distance(p1,p2);
cout<<"res = "<<res<<endl;
运行结果:
(1.1,2.2)
(1.1,3.3)
res = 1.1
总结:
友元函数friend函数,从目前来看它,的不同之处在于,它可以访问private的成员。
  • 运算符重载
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
情景1,成员函数重载
class Complex
{
public:
Complex(float xx=0,float yy=0)
:x(xx),y(yy){}
void dis();
Complex operator+(const Complex &another);
private:
float x,y;
};
void Complex::dis()
{
cout<<"x="<<x<<"t"<<"y="<<y<<endl;
}
Complex Complex::operator+(const Complex &another)
{
return Complex(this->x+another.x,this->y+another.y);
}
main:
Complex p1(1.1,2.2);
Complex p2(1.1,0.0);
p1.dis();
p2.dis();
Complex p3 = p1+p2;
p3.dis();
运行结果 :
x=1.1 y=2.2
x=1.1 y=0
x=2.2 y=2.2

情景2,友元函数重载
class Complex
{
public:
Complex(float xx=0,float yy=0)
:x(xx),y(yy){}
void dis();
friend Complex operator+(Complex &a,Complex &b);
private:
float x,y;
};
void Complex::dis()
{
cout<<"x="<<x<<"t"<<"y="<<y<<endl;
}
Complex operator+(Complex &a,Complex &b)
{
return Complex(a.x+b.x,a.y+b.y);
}
main:
Complex p1(1.1,2.2);
Complex p2(1.1,0.0);
p1.dis();
p2.dis();
Complex p3 = p1+p2;
p3.dis();
运行结果:
x=1.1 y=2.2
x,1.1 y=0
x=2.2 y=2.2

继承Inherit

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
情景1,
class People
{
public:
void eat(string food)
{
cout<<"I am eating : "<<food<<endl;
}
};
class Student :public People
{
public:
void study(string subject)
{
cout<<"I am studying : "<<subject<<endl;
}
};
class Teacher :public People
{
public:
void teach(string subject)
{
cout<<"I am teaching : "<<subject<<endl;
}
};
main:
Student s;
Teacher t;
s.eat("Student");
s.study("China");
cout<<"------------------"<<endl;
t.eat("Teacher");
t.teach("English");
运行结果:
I am eating : Student
I am studying : China
------------------
I am eating : Teacher
I am teaching : English

情景2,看一下继承与虚继承之间的差异。
class Base
{
public:
Base(int d = 10)
:data(d){}
void dis()
{
cout<<"Base data = "<<data<<endl;
}
int data;
};
class A :virtual public Base
{
public:
A()
{
cout<<"A() Base data = "<<data<<endl;
}
void set_data(int d)
{
data = d;
}
};
class B:virtual public Base
{
public:
B()
{
cout<<"B() Base data = "<<data<<endl;
}
int get_data()
{
return data;
}
};
class C:public A,public B
{
public:
C()
{
cout<<"C() Base data = "<<data<<endl;
}
void dis()
{
cout<<"C() data = "<<data<<endl;
cout<<"A() data = "<<data<<endl;
cout<<"B() data = "<<data<<endl;
}

};
main:
C c;
c.dis();
运行结果:
A() Base data = 10
B() Base data = 10
C() Base data = 10
C() data = 10
A() data = 10
B() data = 10
总结,这里假如没有virtual修饰的话,class C中想要输出data的值是,会出现"data is ambiguous"的这种关键字样。这个data,它,不知道应该从class A,还是从class B中获取的。
原文地址:https://www.cnblogs.com/lijianming180/p/12347537.html