C++-Record35—继承和组合混搭情况下的构造和析构;继承中的同名处理;static关键字

目录

继承和组合混搭情况下的构造和析构     

继承中的同名成员变量和同名成员函数的处理

派生类中的static关键字

概念

总体代码


继承和组合混搭情况下的构造和析构     

  调用顺序原则:先构造父类,再构造成员变量、最后构造自己; 先析构自己,在析构成员变量、最后析构父类。

先调用老爹的构造函数,再调用自己的,如果老爹的类中还有父亲,就继续调用老爹的老爹的构造函数。析构函数与此相反。

构造顺序:爷爷(爷爷有爸爸的话,再从爷爷的爸爸的构造函数开始构造)的构造函数->爸爸的构造函数->自己的构造函数;析构的顺序与此相反。

 先看一个案例:

这个称为老祖宗类:

class Object
{
public:
	Object(int a, int b)
	{
		this->a = a;
		this->b = b;
		cout<<"object构造函数 执行 "<<"a"<<a<<" b "<<b<<endl;
	}
	~Object()
	{
		cout<<"object析构函数 \n";
	}
protected:
	int a;
	int b;
};

这个成为父类: 

class Parent : public Object
{
public:
	Parent(char *p) : Object(1, 2)
	{
		this->p = p;
		cout<<"父类构造函数..."<<p<<endl;
	}
	~Parent()
	{
		cout<<"析构函数..."<<p<<endl;
	}

	void printP(int a, int b)
	{
		cout<<"我是爹..."<<endl;
	}

protected:
	char *p;
	
};

下面的子类中,保护父类的对象,也包含父类的父类的对象:

class child : public Parent
{
public:
	child(char *p) : Parent(p) , obj1(3, 4), obj2(5, 6)
	{
		this->myp = p;
		cout<<"子类的构造函数"<<myp<<endl;
	}
	~child()
	{
		cout<<"子类的析构"<<myp<<endl;
	}
	void printC()
	{
		cout<<"我是儿子"<<endl;
	}
protected:
	char *myp;
	Object obj1;
	Object obj2;
};

主函数调用:

 void objplay()
{
	child c1("继承测试");
}
void main()
{
	objplay();
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

运行如下:

继承中的同名成员变量和同名成员函数的处理

当子类中的成员变量与父类中的成员变量的名称相同的时候,该怎么办呢?

答,当子类成员变量与父类成员变量同名时:子类依然从父类继承同名成员。只不过在使用的时候,应该注意,在子类中通过作用域分辨符::进行同名成员区分(在派生类中使用基类的同名成员,显式地使用类名限定符),并且,同名成员存储在内存中的不同位置。

 以上图中的代码为例进行说明,如图中的derived类继承了base类中的属性,base类中原来就有变量b,而derived类中又新定义了一个变量b,那这俩应该如何区分呢?首先,要明白的是,既然是继承关系,那么derived类中肯定是可以调用base类中的变量b的,最关键的是要进行区分,如果是调用base类中的b,应该这么操作"d.base::b = 2;",如果是用derived类新定义的b,就应该是"d.b = 3;"。即:同名成员变量和成员函数通过作用域分辨符进行区分。

默认情况下,访问的都是子类中新定义的属性

派生类中的static关键字

概念

  • 基类定义的静态成员,将被所有派生类共享
  • 根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具有不同的访问性质 (遵守派生类的访问控制)
  •  派生类中访问静态成员,用以下形式显式说明:

                         类名 :: 成员

        或通过对象访问    对象名 . 成员

静态成员变量必须要初始化,这是要告诉编译器千万要给其分配内存空间。

 

举个例子,定义一个A类,定义好了一个静态成员变量a,之后如下:

class A
{
public:
	static int a;
	int b;
public:
	void get()
	{
		cout<<"b "<<b<<endl;
	}
	void print()
	{
		cout<<"AAAAA "<<endl;
	}
protected:
private:
};

int A::a = 100; //这句话 不是简单的变量赋值 更重要的是 要告诉C++编译器 你要给我分配内存 ,我再继承类中 用到了a 不然会报错..

static关键字仍然遵循派生类的访问控制原则,比如说创建一个子类私有继承a类,那么这个子类,就只能在类的内部使用变量a,而不能外部使用:

class B : private A
{

public:
	int b;
	int c;
public:
	void get_child()
	{
		cout<<"b "<<b<<endl;
		cout<<a<<endl;
	}
	void print()
	{
		cout<<"BBBB "<<endl;
	}
protected:
private:
};

 而在类的外部,是不能被调用的:

void main01()
{
	B  b1;
	b1.a = 200;   //这句话写在了类的外部
	system("pause");
}

这样,会报错。 

下面来看下,如果不给静态变量初始化,把代码中的这行给注销掉,会有什么影响:

//int A::a = 100; 

再创建一个主调函数,编译父类创建的对象和子类创建的对象,都没问题:

void main()
{
	A a1;
	a1.print();

	system("pause");
}

但是,当用编译父类所创建的子类所创建的对象的时候,发现编译不通过了:

void main()
{
	B b1;
	b1.get_child();
	system("pause");
}

 这是因为,由于定义在父类中的静态变量a,没有进行初始化,没有进行内存的分配,就仅仅存在于代码区,而子类中,真遇到需要调用的时候,发现在内存中找不到了变量a,所以才会通过不了。

所以:

int A::a = 100; 

这句话不是简单的变量赋值 更重要的是:要告诉C++编译器你要给我分配内存 ,我再继承类中用到了a不然会报错。

下面再继续讨论,如果在A类中再添加一个构造函数,发现运行还是报错:

class A
{
	A()
	{
		cout<<"A的构造函数"<<endl;
	}
public:
	static int a;
	int b;
public:
	void get()
	{
		cout<<"b "<<b<<endl;
	}
	void print()
	{
		cout<<"AAAAA "<<endl;
	}
protected:
private:
};

int A::a = 100;

这是为什么呢?这是因为构造函数前没加上“public”,那编译器就会默认为这个构造函数是私有的,所以,子类无法访问A类的构造函数,整个A类都不能被继承了。当然,单例场景下,构造函数是应该做出私有的,其他场景都应该是共有的!

总结如下:

//1 static关键字 遵守  派生类的访问控制规则

//2  不是简单的变量赋值 更重要的是 要告诉C++编译器 你要给我分配内存 ,我再继承类中 用到了a 不然会报错..

//3 A类中添加构造函数 
	//A类的构造函数中   A的构造函数是私有的构造函数 ... 
	//被别的类继承要小心....
	//单例场景 .... UML

总体代码

dm06_继承和组合混搭下的构造和析构.cpp


#include <iostream>
using namespace std;

class Object
{
public:
	Object(int a, int b)
	{
		this->a = a;
		this->b = b;
		cout<<"object构造函数 执行 "<<"a"<<a<<" b "<<b<<endl;
	}
	~Object()
	{
		cout<<"object析构函数 \n";
	}
protected:
	int a;
	int b;
};


class Parent : public Object
{
public:
	Parent(char *p) : Object(1, 2)
	{
		this->p = p;
		cout<<"父类构造函数..."<<p<<endl;
	}
	~Parent()
	{
		cout<<"析构函数..."<<p<<endl;
	}

	void printP(int a, int b)
	{
		cout<<"我是爹..."<<endl;
	}

protected:
	char *p;
	
};


class child : public Parent
{
public:
	child(char *p) : Parent(p) , obj1(3, 4), obj2(5, 6)
	{
		this->myp = p;
		cout<<"子类的构造函数"<<myp<<endl;
	}
	~child()
	{
		cout<<"子类的析构"<<myp<<endl;
	}
	void printC()
	{
		cout<<"我是儿子"<<endl;
	}
protected:
	char *myp;
	Object obj1;
	Object obj2;
};


void objplay()
{
	child c1("继承测试");
}
void main()
{
	objplay();
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

 dm08_继承中的static关键字.cpp


#include <iostream>
using namespace std;

//单例
class A
{
	A()
	{
		cout<<"A的构造函数"<<endl;
	}
public:
	/*
	static int a;
	int b;
	*/
public:
	/*
	void get()
	{
		cout<<"b "<<b<<endl;
	}
	void print()
	{
		cout<<"AAAAA "<<endl;
	}
	*/
protected:
private:
};

//int A::a = 100; //这句话 不是简单的变量赋值 更重要的是 要告诉C++编译器 你要给我分配内存 ,我再继承类中 用到了a 不然会报错..


/*
class B : private A
{

public:
	int b;
	int c;
public:
	void get_child()
	{
		cout<<"b "<<b<<endl;
		cout<<a<<endl;
	}
	void print()
	{
		cout<<"BBBB "<<endl;
	}
protected:
private:
};
*/

//1 static关键字 遵守  派生类的访问控制规则

//2  不是简单的变量赋值 更重要的是 要告诉C++编译器 你要给我分配内存 ,我再继承类中 用到了a 不然会报错..

//3 A类中添加构造函数 
	//A类的构造函数中   A的构造函数是私有的构造函数 ... 
	//被别的类继承要小心....
	//单例场景 .... UML

void main()
{
	A a1;
	//a1.print();

	 //B b1;
	// b1.get_child();
	system("pause");
}

void main01()
{
	// B  b1;
	 //b1.a = 200;
	system("pause");
}

dm08_继承中的static关键字.cpp


#include <iostream>
using namespace std;

//单例
class A
{
	A()
	{
		cout<<"A的构造函数"<<endl;
	}
public:
	/*
	static int a;
	int b;
	*/
public:
	/*
	void get()
	{
		cout<<"b "<<b<<endl;
	}
	void print()
	{
		cout<<"AAAAA "<<endl;
	}
	*/
protected:
private:
};

//int A::a = 100; //这句话 不是简单的变量赋值 更重要的是 要告诉C++编译器 你要给我分配内存 ,我再继承类中 用到了a 不然会报错..


/*
class B : private A
{

public:
	int b;
	int c;
public:
	void get_child()
	{
		cout<<"b "<<b<<endl;
		cout<<a<<endl;
	}
	void print()
	{
		cout<<"BBBB "<<endl;
	}
protected:
private:
};
*/

//1 static关键字 遵守  派生类的访问控制规则

//2  不是简单的变量赋值 更重要的是 要告诉C++编译器 你要给我分配内存 ,我再继承类中 用到了a 不然会报错..

//3 A类中添加构造函数 
	//A类的构造函数中   A的构造函数是私有的构造函数 ... 
	//被别的类继承要小心....
	//单例场景 .... UML

void main()
{
	A a1;
	//a1.print();

	 //B b1;
	// b1.get_child();
	system("pause");
}

void main01()
{
	// B  b1;
	 //b1.a = 200;
	system("pause");
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值