目录
概念:
有时候当我们需要好几种类的时候,有些类里面的成员可能会存在重复的情况,那就在想有没有一种办法可以,让这些类既有大家都共同拥有的,也要有自己独有的呢? -- 继承
继承后父类的数据A会变成 子类的一部分
class S
{
public:
int a;
};
class W :public S //public为继承的方式
{
public:
int b;
};
访问方式:
不可见意思就是子类的 类外 和 类里都不能访问;protected / private:子类的 类里可以访问,类外不可以。
如果基类成员需要在派生类中被访问,但是又不想被类外访问就定义为protect,这也看出保护成员限定符是因继承才出现的。
class 的默认继承方式是private ;struct 是 public
赋值转换
派生类对象可以赋值给 基类的对象 / 基类的指针 / 基类的引用。把派生类中父类的那部分数据切来赋值过去 (只有公有继承的父子类,才可以实现)
但是父类的对象不能赋值给子类 !
重定义:
如果子类和父类有同名的成员,那么访问子类里的这些数据,会优先访问子类的,屏蔽父类的,这个叫做隐藏,也叫做重定义。(但不建议定义的时候有重名的成员)
class S
{
public:
void f()
{
cout << "Hello !" << endl;
}
};
class M :public S
{
public:
void f(int)
{
cout << "Hello !" << endl;
}
};
int main()
{
S a;
M b;
a.f();
b.f();
b.f(8);
return 0;
}
可以看到这里的f函数也是 隐藏(重定义) 。
不是重载哦 重载需要两个这里的两个函数在同一作用域里面。
这个代码是无法正常允许的,会在编译的时候出错。
友元:
友元没有传递的这个说法,一个函数/类是父类的友元,但不是它不会是派生类的友元
友元关系不会被继承!!!!
派生类的friend函数可以访问派生类本身的一切变量,包括从父类继承下来的protected域中的变量。但是对父类来说,他并不是friend的。
class B;
class A
{
friend B;
private:
int a;
};
class B : public A
{
public:
void fun()
{
cout << a;
}
int b;
};
这段代码中 数据a 是被private限定的,无论什么继承都是private,不能访问的,但是如果我让子类B成为了父类A的友元,就可以在B类里面访问了,当然类外依旧是不可以的!!!
静态成员:
在继承中,静态成员,父类和子类都可以访问,属于是共用的
class A
{
public:
static void dunc()
{
cout << "Hello" << endl;
}
int a;
};
class B : public A
{
public:
int b;
};
int main()
{
B::dunc();
return 0;
}
默认函数:
子类会优先调用父类的构造函数初始化那些继承自父类的成员,然后再初始化自己的。
class S
{
public:
S(int num )
{
x = num;
}
int x;
};
class M :public S
{
public:
M(int m = 11, int n = 22)
: y(n),
x(m)
{ }
int y;
};
int main()
{
M b;
return 0;
}
这个代码是会报错的哦。S类没有构造函数,而子类会优先调用父类的构造,就报错了,还有一个错误:
这个可以这样解决(赋值 拷贝构造函数也是这样):
class S
{
public:
S(int num)
{
x = num;
}
int x;
};
class M :public S
{
public:
M(int m = 11, int n = 22)
: y(n),
S(m)
{ }
int y;
};
int main()
{
M b;
return 0;
}
当然这样 x 就变成11了,这里依然也是先调用S的构造函数,初始化列表初始化顺序是看变量的声明顺序的,默认继承自父类的成员是最前的
class S
{
public:
S(int num)
{
x = num;
}
S(const S& data)
{
x = data.x;
}
S& operator=(const S& data)
{
if (this != &data)
{
x = data.x;
}
}
int x;
};
class M :public S
{
public:
M(int m = 11, int n = 22)
: y(n),
S(m)
{ }
M(const M& data)
:S(data.x),
y(data.y)
{ }
M& operator=(const M& data)
{
if (this != &data)
{
S::operator=(data.x);
y = data.y;
}
}
int y;
};
拷贝构造函数需要声明是父类的,不然会和子类的拷贝构造函数构成 隐藏
子类的析构函数不需要显示的调用父类的析构函数:
① 显示调用如果不声明会构成 隐藏 :因为多态的需要,析构函数名会被统一为destructor()
② 即使你声明了是调用父类的析构,因为析构顺序就是先子后父,子类析构完会自动调用父类的