目录
继承和组合混搭情况下的构造和析构
调用顺序原则:先构造父类,再构造成员变量、最后构造自己; 先析构自己,在析构成员变量、最后析构父类。
先调用老爹的构造函数,再调用自己的,如果老爹的类中还有父亲,就继续调用老爹的老爹的构造函数。析构函数与此相反。
构造顺序:爷爷(爷爷有爸爸的话,再从爷爷的爸爸的构造函数开始构造)的构造函数->爸爸的构造函数->自己的构造函数;析构的顺序与此相反。
先看一个案例:
这个称为老祖宗类:
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");
}