【C++之继承和派生、同名隐藏、赋值兼容性规则】

1.面向对象的三大特征: 封装,继承和派生,多态性 封装: 封装:(Encapsulation)是面向对象程序设计最基本的特性,把数据(属性)和函数(方法,操
作)合成一个整体,这在计算机世界中是用类与对象实现的。

继承和派生:(继承和派生一体两面)

继承(inheritance)机制:是类型层次结构设计中实现代码的复用重要手段。
派生:保持原有类特性的基础上进行扩展,增加新属性和新方法,从而产生新的类型。
在面向对象程序设计中,继承和派生是构造出新类型的过程。呈现类型设计的层次结构,体现了程序设计人员对现实世界由简单到复杂的认识过程。

  1. 不论采取何种继承方式,基类中所有数据成员都将继承到派生类

class student : person // 冒号后没有属性默认是私有
struct student : person // 冒号后没有属性默认是公有。

using namespace std;
class person
{
private:
	int id ;
public:
	 char  name[10];
protected:
	int age;
public:
	person(int x,const char * y,int z):id(x),age(z)
	{	
		strcpy_s(name, strlen(y)+1, y);
		cout << "Create person " << endl;
	}
	~person()
	{}
	void fun()
	{
		cout << "人跳舞" << endl;
	}
	void print()
	{
		cout << "name " <<name<<"age  "<<age << endl;
	}
};
class student  : person  
{
private:
	int id;	
public:
	char name[10];
protected:
	int sex;
public:
	student(int x,const char *  y,int z):person(202207,"ss",22),id(x),sex(z)
	{       
		strcpy_s(name, strlen(y) + 1, y);
		cout << "Create stundet" << endl;
	}
	student() :person(202207, "ss", 22), name(), sex()
	{
		cout << "Create stundet" << endl;
	}
	~student() {}
	void print()
	{
		cout  << "  name :"<<name<<"  sex :" << sex <<"  id : " <<id <<endl;
		cout << "  name :" << person::name << "  age :" << person::age << endl;
		//cout << "person  id :" <
	}
};
int main()
{
	person person1(202201,"yhping",12);
	student student1(202002,"lmy",1);
	student1.print();
}

student(int x,const char * y,int z):person(202207,"ss",22),id(x),sex(z) {} 中基类无名对象person也可以不初始化 :----> person(id,name,age)

  1. 在类型的继承层次结构中,保护属性当作公有属性来使用
  2. 继承性具有传递性。
  3. 无论采取何种继承方式,派生类对象的成员方法都可以去访问基类对象中的保护和公有属性!!!!!!!!!!!!!!!!!!!!!!!!!!!

那怎么可以访问基类的私有属性呢?

【C++之继承和派生、同名隐藏、赋值兼容性规则】_第1张图片
无论是内部还是外部都需要调动成员方法才能改私有属性。

我们可以通过调动派生类对象的方法,在里面再去调动person类的方法。

class person
{
private:
	int p1 ;
public:
	 char  p2[10];
	 int weight=90;
protected:
	int p3;
public:
	void fun1()
	{
		p1 = 19940811;
		p3 = 180;
	}
	const int& get_p1()const
	{
		return p1;
	}
};
class student : public person
{
private:
	int id;
	person person_one;
public:
	char name[10];
	int  high;
	
protected:
	int sex;
public:
	int get_p1()const
	{
		return id;
	}
	void fun()
	{
		const char* p = "zhangsanfeng";
		person_one.weight = 1000;
		strcpy_s(person::p2, strlen(p) + 1, p);
		person::fun1();//通过fun1()的方法去访问私有属性
		int val=person::get_p1();//通过此方法得到私有属性的值。
		printf("%d", val);
	}
};
int main()
{
	person person1(202201,"yhping",12);
	student student1(202002,"lmy",1,person1);
	student1.high = 180;
	student1.fun();
}

用fun函数初始化基类的person对象(注意不是student类里的基类person)

	student(int x,const char *  y,int z):person(id,name,age),id(x),sex(z)//这里的id,name,age 的是一个变量,不是person的属性!
	{
		strcpy_s(name, strlen(y) + 1, y);
		cout << "Create stundet" << endl;
	}
	void fun()
	{
		//person::id = 2008;
		const char* p = "zhangsanfeng";
		strcpy_s(person::name, strlen(p) + 1, p);
		person::age = 18;
	}

【C++之继承和派生、同名隐藏、赋值兼容性规则】_第2张图片
可以看到person类里的公有和保护都可以正常访问。

void fun()
	{
		person::id = 2008;
		const char* p = "zhangsanfeng";
		strcpy_s(person::name, strlen(p) + 1, p);
		person::age = 18;
	}

这里看看能不能访问私有id的属性;(不可访问)

在这里插入图片描述
我们把属性换成public试试:(结果还是不能)
【C++之继承和派生、同名隐藏、赋值兼容性规则】_第3张图片
在这里插入图片描述


using namespace std;
class person
{
private:
	int p1 ;
public:
	 char  p2[10];
protected:
	int p3;
public:

};
class student  : public person
{
private:
	int id;
	
public:
	char name[10];
protected:
	int sex;
public:
	void fun()
	{
		//person::p1 = 987654;  //无法访问p1
		const char* p = "zhangsanfeng";
		strcpy_s(person::p2, strlen(p) + 1, p);
		person::p3 = 18;
	}	
};
int main()
{
	person person1(202201,"yhping",12);
	student student1(202002,"lmy",1);
	person1.fun1();
	student1.print();
}

person1内存结构:
【C++之继承和派生、同名隐藏、赋值兼容性规则】_第4张图片
student1内存结构:【C++之继承和派生、同名隐藏、赋值兼容性规则】_第5张图片

p1为什么无法访问?
【C++之继承和派生、同名隐藏、赋值兼容性规则】_第6张图片

继承来的对象与成员对象的区别(访问控制)

我们准备访问student中基类(person)的保护属性student类中的对象(person_one)属性中的保护属性( p 3 ),观察是否都能访问。

class person
{
private:
	int p1 ;
public:
	 char  p2[10];
protected:
	int p3;
public:
	person(int x,const char * y,int z):p1(x),p3(z)
	{
		
		strcpy_s(p2, strlen(y)+1, y);
		cout << "Create person " << endl;
	}
	{}
};
class student  : public person
{
private:
	int id;
	
public:
	char name[10];
	person person_one;
protected:
	int sex;
public:
	student(int x,const char *  y,int z,person &s1):person(x,y,z),id(x),sex(z),person_one(s1)
	{
		strcpy_s(name, strlen(y) + 1, y);
		cout << "Create stundet" << endl;
	}

	void print()
	{
		//cout  << "  name2 :"<
		cout << " person继承       p3(保护) :" << p3 << endl;
		cout << " person_one属性   p2(公有) "<<person_one.p2 << endl;
	}
};
int main()
{
	person person1(202201,"yhping",12);
	student student1(202002,"lmy",1,person1);
	student1.print();
}

【C++之继承和派生、同名隐藏、赋值兼容性规则】_第7张图片

我们可以看到,继承来的person可以访问保护属性,student类里的person_one成员属性中的公有也可访问。


但是唯独student类里的person_one成员属性中的保护和私有是不可访问的。
【C++之继承和派生、同名隐藏、赋值兼容性规则】_第8张图片
【C++之继承和派生、同名隐藏、赋值兼容性规则】_第9张图片

总结:

1基类的可访问性控制
无论采取何种继承方式,派生类对象的成员方法都可以去访问基类对象中的保护和公有属性。外部 “.”(点)+属性的方式无法访问基类。

2.类类型的可访问性控制
(对于类类型来说,不管其属性是公有私有还是保护,设置的作用是控制外部对其访问的权限。对内部来说,无论采取何种继承方式,保护和私有都是不可访问的。)

3怎么访问私有属性?(不管继承类型是私有和保护都可行)()
无论是内部还是外部都需要调动成员方法才能改私有属性。

“不管其属性是公有私有还是保护,设置的作用是控制外部对其访问的权限”这句话举个例子:

class person
{
private:
	int p1 ;
public:
	 char  p2[10];
	 int weight=90;
protected:
	int p3;
};
class student : private person
{
private:
	int id;	
public:
	char name[10];
	int  high;
	person person_one;
protected:
	int sex;
	
public:
	student(int x,const char *  y,int z,person &s1):person(x,y,z),id(x),sex(z),person_one(s1)
	{
		strcpy_s(name, 10, y);
		
		cout << "Create stundet" << endl;
	}
	void fun()
	{
		const char* p = "zhangsanfeng";
		printf("%d", person_one.weight);
		
	}
};
int main()
{
	person person1(202201,"yhping",12);
	student student1(202002,"lmy",1,person1);
	student1.fun();
	student1.person_one.weight = 0;//ok
	student1.person_one.p3= -1;//error


}

【C++之继承和派生、同名隐藏、赋值兼容性规则】_第10张图片

person_one的属性如果是protected,那么student1.person_one.weight = 0;也是无法通过的。

同名隐藏

3.同名隐藏(成员属性和成员方法)。(就近原则的机制,会调动离自己最近的成员方法。)

using namespace std;

#if 1
class Object
{
public:
	int value;
public:
	Object(int x = 0) :value(x) {}
	~Object() {}
	void print(int x)
	{
		value = x;
		cout << value << endl;
		printf("OBJECT");
	}
};
class Base : public Object
{
public:
	int value;
public:
	Base(int x = 0) : Object(x), value(x + 10) {}
	~Base() {}
	void print()
	{
		value += 10;
		Object::value += 10;
		printf("BASE");
	}
};
int main()
{
	Base base(100);
	base.print();
	//base.Object::print(10);
	
	return 0;
}

结果输出是“BASE”


另一种情况:

class Object
{
public:
	int value;
public:
	Object(int x = 0) :value(x) {}
	~Object() {}
	void print(int x)
	{
		value = x;
		cout << value << endl;
		printf("OBJECT");
	}
};
class Base : public Object
{
public:
	int value;
public:
	Base(int x = 0) : Object(x), value(x + 10) {}
	~Base() {}
	void print()
	{
		value += 9;
		Object::value += 10;
		printf("BASE");
	}
};
int main()
{
	Base base(100);
	base.print(10);//error 
	return 0;
}

我们想进行函数的重载那样进行类同名方法的重载,可现实确不被允许。
想调用基类的方法可以这样:base.Object::print(10);

赋值兼容性规则

C++面向对象编程中一条重要的规则是:公有继承意味着 “是一个” 。一定要牢牢记住这条规则。
1.赋值的切片

派生类的对象可以赋值给基类的对象,这时是把派生类对象中从对应基类中继承来的隐藏对象赋值 给基类对象。反过来不行,因为派生类的新成员无值可赋。
在这里插入图片描述
在这里插入图片描述
基类object 受保护,不能对其赋值,不能将地址赋
注意:赋值性规则2条:只能把子给给父 2.只能是公有类型!

class Object
{
public:
	int value;
public:
	Object(int x ) :value(x) {}
	~Object() {}
	void print()
	{
		cout <<"OBJECT"<< value << endl;
	}
};
class Base : public Object
{
public:
	int num;
public:
	Base(int x = 0) : Object(x), num(x + 10) {}
	~Base() {}
	void print()
	{
		cout << "base.value"<<value << endl;	
	}
};
int main()
{
	Base base(100);
	Object object(1000);
	//object = base;//切片现象。
	object.print();
	base.print();
	return 0;
}

在这里插入图片描述
而赋值会产生切片现象,即把基类的属性值赋值给基类对象的属性值。而子对象派生的属性不会赋值出去。

举个例子,人对象和学生对象,学生是人,人不一定是学生。从世界实际来说父赋值给子是不成立的。第二,新派生的值没有办法给。

【C++之继承和派生、同名隐藏、赋值兼容性规则】_第11张图片

2.传地址和引用的切片
问:类型对指针的约束能力

1.指针加一的能力 ,2。指针解析的能力

Base base(100);
	Object object(1000);
	Object* p = &base;
	Object& ip = base;
	ip.value = 999;
	cout << ip.value << endl;
	return 0;

看看两个对像的大小:
【C++之继承和派生、同名隐藏、赋值兼容性规则】_第12张图片

Object* p = &base; // obj在解引用时只能解析到看到的4字节空间,所以解析不到base 派生的num的值。

你可能感兴趣的:(C++学习总结,c++,开发语言)