公有/私有/保护成员
在关键字public后面声明,它们是类与外部的接口,任何外部函数都可以访问公有类型数据和函数。
在关键字private后面声明,只允许本类中的函数访问,而类外部的任何函数都不能访问。
在关键字protected后面声明,与private类似,其差别表现在继承与派生时对派生类的影响不同
公有/私有/保护继承
private成员任何形式继承
,均不可访问。private继承,所有成员私有化。protected继承,public转为protected。
#include <iostream>
using namespace std;
class Base
{
public:
int x_;
protected:
int y_;
private:
int z_;
};
class PublicInherit : public Base
{
public:
void Test()
{
x_ = 10;
y_ = 20;
//z_ = 30; error
}
private:
int a_;
};
class PublicPublicInherit : public PublicInherit
{
public:
void Test()
{
y_ = 20;
}
};
class PrivateInherit : private Base
{
public:
void Test()
{
x_ = 10;
y_ = 20;
//z_ = 30; error
}
};
int main(void)
{
PublicInherit pub;
pub.x_ = 20;
PrivateInherit pri;
//pri.x_ = 10; error
return 0;
}
只能在初始化列表的成员
const 常量
引用
类的成员没有默认构造函数
基类没有默认构造函数的时候,基类的构造函数要在派生类构造函数初始化列表中调用
创建对象时,要初始类成员的每一个成员,如果没有在初始化列表里面,编译器会自动使用它的默认的构造函数进行初始化
,但是它没有默认构造函数,所以会编译报错。
Base(const Base &other) : objb_(other.objb_), b_(other.b_)
{
}
Derived(const Derived &other) : d_(other.d_), objd_(other.objd_), Base(other)
{
}
派生类的拷贝构造函数,基类没有默认拷贝构造函数的时候,也需要调用基类的拷贝构造函数
继承与组合
无论是继承与组合,两者都需要使用构造函数的初始化列表去构造这些对象
。
组合是has-a的关系。通常是在希望新类内部具有已存在的类的功能时使用,而不是希望已存在类作为它的接口。组合通过嵌入一个对象以实现新类的功能,而新类用户看到的是新定义的接口
,而不是来自老类的接口。
继承是is-a的关系。如果希望新类与已存在的类有相同的接口
,在这基础上可以增加自己的成员。这时候需要用继承。
#include <iostream>
using namespace std;
class Base
{
public:
Base() : x_(0), y_(48)
{
}
int GetBaseX() const
{
return x_;
}
int GetBaseY() const
{
return y_;
}
void Show()
{
cout << "Base::Show ..." << endl;
}
int x_;
private:
int y_; //继承后无法被直接访问,可通过GetBaseY访问
};
class Derived : public Base
{
public:
Derived() : x_(0)
{
}
int GetDerivedX() const
{
return x_;
}
void Show(int n)//与下面的show 构成重载,基类的show被隐藏
{
cout << "Derived::Show " << n << endl;
}
void Show()
{
cout << "Derived::Show ..." << endl;
}
int x_; //重定义x_,基类的x_被隐藏
};
//组合关系
class Test
{
public:
Base b_;
int x_;
};
int main(void)
{
Derived d;
d.x_ = 10;
d.Base::x_ = 20; //访问被隐藏的基类x_;
cout << d.GetBaseX() << endl;
cout << d.GetDerivedX() << endl;
cout << d.GetBaseY() << endl;
d.Show();
d.Base::Show();//访问被隐藏的基类show
cout << sizeof(Base) << endl;
cout << sizeof(Derived) << endl;
cout << sizeof(Test) << endl;
Test t;
cout << t.x_ << endl;
cout << t.b_.GetBaseX() << endl;
cout << t.b_.GetBaseY() << endl;
return 0;
}
程序输出
20
10
48
Derived::Show ...
Base::Show ...
8
12
12
-858993460
0
48
构造函数是为了保证对象的每个数据成员都被正确初始化
,无参的默认构造函数,x被初始化为任意值。
overload/overwrite/override之间的区别
重载(overload)成员函数
- 相同的范围(在同一个类中)
- 函数名字相同
参数不同
- virtual关键字
可有可无
覆盖(override)派生类与基类
- 不同的范围(分别位于派生类与基类)
- 函数名字相同
参数相同
- 基类函数必须
有virtual关键字
隐藏(overwrite)(派生类与基类)
- 不同的范围(分别位于派生类与基类)
函数名与参数都相同,基类无virtual关键字
函数名相同,参数不同,virtual可有可无
当隐藏发生时,实际上是继承了但不可见。隐藏的数据成员,仍然占内存空间。如果在派生类的成员函数中想要调用基类的被隐藏函数
,可以使用基类名::函数名(参数)
的语法形式。如果被隐藏的函数是public的,则在类体外
也可以使用派生类对象.基类名::函数名(参数)
的语法,也可用派生类指针->基类名::函数名(参数)
的语法,同理被隐藏的数据成员也可以使用上述列举的方法访问。