目录
1. 实现一个不能被继承的类
如下代码所示
#include<iostream>
#include<algorithm>
using namespace std;
class Teacher
{
private:
Teacher()
{
x = 1;
}
int x;
};
class Student: public Teacher
{
public:
Student()
{
ss = 1;
}
private:
int ss;
};
因为父类构造函数不能调用出错
代码如下
#include<iostream>
#include<algorithm>
using namespace std;
class Teacher final
{
public:
Teacher()
{
x = 1;
}
private:
int x;
};
class Student: public Teacher
{
public:
Student()
{
ss = 1;
}
private:
int ss;
};
不可以将其当做基类(父类)
2. 友元与继承
代码如下
#include<iostream>
#include<algorithm>
using namespace std;
class Student;//提前声明否则友元函数定义找不到Student
class Teacher
{
public:
friend void playval( const Teacher& t, const Student& s);
Teacher(int xx=11)
{
x = xx;
}
private:
//protected:
int x;
};
class Student: public Teacher
{
public:
Student()
:Teacher(11)
{
ss = 1;
}
private:
int ss;
};
void playval(const Teacher& t,const Student& s )
{
cout << t.x << endl;
cout << s.ss << endl;
}
int main()
{
Teacher t(16);
Student s;
playval(t, s);
}
结果如图,不能找到s的私有成员
如下代码所示
#include<iostream>
#include<algorithm>
using namespace std;
class Teacher
{
public:
Teacher(int xx=11)
{
x = xx;
}
private:
//protected:
int x;
};
class Student: public Teacher
{
public:
friend void inputval(const Teacher& t, const Student& s);
Student()
:Teacher(11)
{
ss = 1;
}
private:
int ss;
};
void inputval(const Teacher& t, const Student& s)
{
cout << t.x << endl;
cout << s.ss << endl;
}
int main()
{
Teacher t(16);
Student s;
inputval(t, s);
return 0;
}
结果如下图所示子类的友元函数找不到其父类的私有与保护成员
3.继承与静态成员
如下代码所示
#include<iostream>
using namespace std;
class Teacher
{
public:
string _name;
static int _count;
};
int Teacher::_count = 0;
class Student : public Teacher
{
protected:
int _stuNum;
};
int main()
{
Teacher t;
Student s;
// 这⾥的运⾏结果可以看到⾮静态成员_name的地址是不⼀样的
// 说明⼦类继承下来了,⽗⼦类对象各有⼀份
cout << &t._name << endl;
cout << &s._name << endl;
// 这⾥的运⾏结果可以看到静态成员_count的地址是⼀样的
// 说明⼦类和⽗类共⽤同⼀份静态成员
cout << &t._count << endl;
cout << &s._count << endl;
// 公有的情况下,⽗⼦类指定类域都可以访问静态成员
cout << Teacher::_count << endl;
cout << Student::_count << endl;
return 0;
}
运行结果如下
我们可以看到子类对象中的_name与父类对象中的_name地址不同,而子类对象与父类对象的_count地址是相同的。说明父类对象与子类对象共用一个静态成员。
4.多继承及其菱形继承问题
(1). 继承模型
如下图
如下图
在内存中的分布如下
代码演示
#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
string _name; // 姓名
};
class Student : public Person
{
protected:
int _num;
};
class Teacher : public Person
{
protected:
int _id;
};
class headmaster : public Student, public Teacher
{
protected:
string _Course;
};
上述代码即为一个菱形继承
int main()
{
// 编译报错: 对“_name”的访问不明确
headmaster a;
a._name = "peter";
return 0;
}
这样调用编译会报错
编译器不知道调用的是哪个父类中的_name
我们可以通过显式指定访问那个父类的成员来解决二义性的问题,但是无法解决数据冗余的问题
int main()
{
//
a.Student::_name = "xxx";
a.Teacher::_name = "yyy";
return 0;
}
(2). 虚继承
using namespace std;
class Person
{
public:
string _name; // 姓名
};
class Student : virtual public Person
{
protected:
int _num;
};
class Teacher : virtual public Person
{
protected:
int _id;
};
class headmaster : public Student, public Teacher
{
protected:
string _Course;
};
int main()
{
headmaster h;
h._name = "lisi";
cout << h._name << endl;
h.Student::_name = "l";
cout << h._name << endl;
h.Teacher::_name = "s";
cout << h._name << endl;
cout << &h._name << endl;
cout << &h.Student::_name << endl;
cout << &h.Teacher::_name << endl;
return 0;
}
输出结果如下
可以看到这三个在内存中用了一个地址空间,这样解决了二义性和数据冗余的问题
(2.1)虚继承解决数据冗余和二义性的原理
如下代码
#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
int a;
};
class Student : virtual public Person
{
public:
int _num;
};
class Teacher : virtual public Person
{
public:
int _id;
};
class headmaster : public Student, public Teacher
{
public:
int test;
};
int main()
{
headmaster h;
h.Student::a = 1;
h.Teacher::a = 2;
h._num = 3;
h._id = 4;
h.test = 5;
return 0;
}
在内存中如下所示
内存2是p1指向的地址,内存3是p2指向的地址它们下面指针的指向是相同的
Teacher和Student自己定义的对象也可以通过这样来找到Person
如下
int main()
{
Teacher t;
Student s;
t.a = 1;
cout << t.a << endl;
s.a = 2;
cout << t.a << endl;
cout << s.a << endl;
return 0;
}
结果为
(3). 多继承中指针偏移问题
关于下面程序说法正确的是
A: p1==p2==p3 B: p1<p2<p3 C: P1==p3!=p2 D: p1!=p2!=p3
class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
int main()
{
Derive d;
Base1* p1 = &d;
Base2* p2 = &d;
Derive* p3 = &d;
return 0;
}
先继承的父类在前面,后继承的父类在后面,子类成员在最后面,所以p1与p3指向相同
选C
(4). IO库中的菱形虚拟继承
template<class CharT, class Traits = std::char_traits<CharT>>
class basic_ostream : virtual public std::basic_ios<CharT, Traits>
{};
template<class CharT, class Traits = std::char_traits<CharT>>
class basic_istream : virtual public std::basic_ios<CharT, Traits>
{};
5. 继承和组合
例如汽车类(car) 和 轮胎类(tire) 适合使用组合方式实现,动物类可以作为狗类的父类(继承思想)
这篇就到这里啦(づ ̄3 ̄)づ╭❤~