代码1: 子类访问限定、继承方式 ,以及 子类和父类复制兼容
#include<iostream>
using namespace std;
//父类和子类是两个独立的作用域
//所以他的属性和方法可以重名
class Person//父类
{
public:
void Print()
{
cout << "name:" << _name << endl;
cout << "age:" << _age << endl;
}
protected:
string _name = "peter";
public:
int _age = 18;
//private成员在子类中不能直接访问
//但可以间接获取,例如 Get
};
class Student :protected Person//子类 继承方式
{
protected:
int _stuid;
};
class Teacher :public Person
{
protected:
int _jobid;
};
// 父类为struct ,子类默认继承方式和访问限定符都是公有的
// 父类为class ,子类默认继承方式和访问限定符都是私有的
struct other :public Person//默认public
{
//public
};
int main()
{
Student s;
Teacher t;
//s.Print();//public+protected = protected (在类外面不能访问)
t.Print();// publuc+public
Person p = t;
//Person p = s; protected 不能访问
//子类可以直接赋值给父类,但是受限制,只有子类的 成员或函数 是 公有public才能
//每个子类对象都是一个特殊的父类对象
//父类=子类 --> 切割/切片
Person& ref = t;
//赋值兼容: 不产生临时变量,不用加 const 修饰
// ref 就是直接指向切片部分
ref._age = 19;//ref可以修改子类(但限制为 public)
return 0;
}
代码2: 父类和子类的显示构造函数、构造顺序、析构顺序
#include<iostream>
using namespace std;
class Person
{
public:
Person(const char* name)
: _name(name)
{
cout << "Person()" << endl;
}
Person(const Person& p)
:_name(p._name)
{
cout << "Person(const Person& p)" << endl;
}
Person& operator=(const Person& p)
{
cout << "Person& operator=(const Person& p)" << endl;
if (this != &p)
_name = p._name;
return *this;
}
~Person()
{
cout << "~Person()" << endl;
}
protected:
string _name = "peter";
};
class Student : public Person
{
public:
// 1.如果 子类没有默认构造函数,并且父类也没有默认构造函数,那么在子类的构造函数中必须 显式调用 父类的特定构造函数,否则编译器会报错。
// 2.若 子类的构造函数中没有 显式调用 父类的 特定构造函数,那么父类会调用 本身的构造函数 ,若父类没有默认构造函数,否则编译器会报错。
Student(const char* Pname, const char* Sname)
:Person(Pname)//显示调用父类构造函数
, _name(Sname)
{
cout << "Student()" << endl;
}
//Student(const Student& s) 不存在深拷贝时,拷贝构造可以不用写
Student(const Student& s)
:Person(s)//子类可以赋值给父类
, _name(s._name)
{
cout << "Student(const Student& s)" << endl;
}
Student& operator=(const Student& s)
{
cout << "Student& operator=(const Student& s)" << endl;
if (this != &s)
{
Person::operator=(s);
//和父类重名,父类函数隐藏
_name = s._name;
}
return *this;
}
~Student()
{
// ~Person(); 此处又不能显示调用
// 子类的析构也会隐藏
// 因为后期多态,析构函数都会被统一处理成 destructor,导致函数重名
// Person::~Person();//即使不写也会自动调用
//写了就进行两次析构 (且析构顺序无法是先子类后父类
//还是要指定作用域
cout << "~Student()" << endl;;;
}
//构造: 先父类后子类
//析构: 先子类后父类
void Print()
{
cout << _name << endl;
cout << Person::_name << endl;;
//直接指定类域进行访问
}
protected:
string _name = "lihua";//属性可以重名
// Person
// 父类+自己,父类的调用父类构造函数初始化(复用)
// 父类成员当成一个整体的自定义成员
};
int main()
{
Student s1("zhangsan", "lisi");//父类 子类
s1.Print();//Person() Student() lisi zhangsan
//当子类和父类属性重名(只看名称),优先访问当前类域(也称隐藏)
cout << endl;
Student s2(s1);
s2.Print();//Person(const Person& p) Student(const Student & s) lisi zhangsan 拷贝构造
cout << endl;
Student s3("wangwu", "zhaoliu");
s3.Print();// Person() Student() 构造 + 构造
cout << endl;
Student s4 = s3;
s4.Print();//Person(const Person& p) Student(const Student & s) 拷贝构造
cout << endl;
Person p("zz");
//p.~Person();//显示调用 Person 的析构函数,多次析构
return 0;
}
代码3: 类中 静态成员的归属
#include<iostream>
using namespace std;
class Student;
class Person
{
public:
Person()
{
_count++;//可以通过静态成员来计算创建成员个数
}
friend void Display(const Person& p, const Student& s);
//友元不能继承
protected:
string _name;
public:
static int _count;//静态成员只有一份,子类和父类共用
//父类静态成员属于当前类,也属于当前类的所有类
};
int Person::_count = 0;
class Student : public Person
{
friend void Display(const Person& p, const Student& s);
protected:
int _stuNum;
//Student 中
};
void Display(const Person& p, const Student& s)
{
cout << p._name << endl;
cout << s._stuNum << endl;
}
int main()
{
Person p;
Student s;
cout << &Person::_count << endl;
cout << &Student::_count << endl;//公用一块空间
return 0;
}
代码4: 菱形继承问题(虚继承)
//单继承/多继承(父类个数是否唯一
//菱形继承: 多继承的特殊情况(见图)
//问题: 1.数据冗余
// 2.二义性
/*
#include<iostream>
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 Assistant : public Student, public Teacher
{
protected:
string _majorCourse; // 主修课程
};
void Test()
{
// 这样会有二义性无法明确知道访问的是哪一个
Assistant a;
a._name = "peter";//Student类和Teacher类都有_name
// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
a.Student::_name = "xxx";
a.Teacher::_name = "yyy";
}
int main()
{
Test();
return 0;
}
以上是关于类的基本定义和基本实现,关于虚函数,可以看我下一篇博客!!!