C++类的继承(听课笔记)

代码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;
}

以上是关于类的基本定义和基本实现,关于虚函数,可以看我下一篇博客!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值