C++中public&protected&private继承

1. 访问权限问题

(1)public继承

class Base{
public:
	void getC(){}
	int c;
protected:
	void getB(){}
	int b;
private:
	void getA(){}
	int a;
};
class Derived : public Base{
public:
	void print(){//派生类内部访问权限测试
		a = 1;  //cannot access private member declared in class 'Base'
		getA(); //cannot access private member declared in class 'Base'
		b = 1;  //ok
		getB(); //ok
		c = 1;  //ok
		getC(); //ok
	}
};
//派生类对象访问权限测试
Derived d;
d.a = 1;        //cannot access private member declared in class 'Base'
d.getA();       //cannot access private member declared in class 'Base'
d.b = 1;        //cannot access protected member declared in class 'Base'
d.getB();       //cannot access protected member declared in class 'Base'
d.c = 1;        //ok
d.getC();       //ok

可见,public继承模式下,派生类内部可以访问基类的protected和public属性的成员;而派生类对象只能访问基类public属性的成员。
(2)protected继承

class Base{
public:
	void getC(){}
	int c;
protected:
	void getB(){}
	int b;
private:
	void getA(){}
	int a;
};
class Derived : protected Base{
public:
	void print(){//派生类内部访问权限测试
		a = 1;  //cannot access private member declared in class 'Base'
		getA(); //cannot access private member declared in class 'Base'
		b = 1;  //ok
		getB(); //ok
		c = 1;  //ok
		getC(); //ok
	}
};
class SubDerived : public Derived{
public:
	void show(){//派生类子类内部访问权限测试
		a = 1;  //cannot access private member declared in class 'Base'
		getA(); //cannot access private member declared in class 'Base'
		b = 1;  //ok
		getB(); //ok
		c = 1;  //ok
		getC(); //ok
	}
};
//派生类对象访问权限测试
Derived d;
d.a = 1;        //cannot access private member declared in class 'Base'
d.getA();       //cannot access private member declared in class 'Base'
d.b = 1;        //cannot access protected member declared in class 'Base'
d.getB();       //cannot access protected member declared in class 'Base'
d.c = 1;        //cannot access public member declared in class 'Base'
d.getC();       //cannot access public member declared in class 'Base'

protected继承模式下,派生类内部可以访问基类的protected和public属性的成员;而派生类对象无法访问基类任何成员;派生类子类内部对基类的访问权限同它的父类。
(3)private继承

class Base{
public:
	void getC(){}
	int c;
protected:
	void getB(){}
	int b;
private:
	void getA(){}
	int a;
};
class Derived : private Base{
public:
	void print(){//派生类内部访问权限测试
		a = 1;  //cannot access private member declared in class 'Base'
		getA(); //cannot access private member declared in class 'Base'
		b = 1;
		getB();
		c = 1;
		getC();
	}
};
class SubDerived : public Derived{
public:
	void show(){//派生类子类内部访问权限测试
		a = 1;  //cannot access private member declared in class 'Base'
		getA(); //cannot access private member declared in class 'Base'
		b = 1;  //'b' not accessible because 'Derived' uses 'private' to inherit from 'Base'
		getB(); //'getC' not accessible because 'Derived' uses 'private' to inherit from 'Base'
		c = 1;  //'c' not accessible because 'Derived' uses 'private' to inherit from 'Base'
		getC(); //'getC' not accessible because 'Derived' uses 'private' to inherit from 'Base'
	}
};
//派生类对象访问权限测试
Derived d;
d.a = 1;        //cannot access private member declared in class 'Base'
d.getA();       //cannot access private member declared in class 'Base'
d.b = 1;        //cannot access protected member declared in class 'Base'
d.getB();       //cannot access protected member declared in class 'Base'
d.c = 1;        //cannot access public member declared in class 'Base'
d.getC();       //cannot access public member declared in class 'Base'

private继承模式下,派生类类内部可以访问基类的protected和public属性的成员;而派生类对象无法访问基类任何成员;派生类子类内部无法访问基类的任何成员


总结:无论哪种继承模式,派生类类内部永远可以访问基类的protected和public属性的成员;public继承模式下,派生类对象只能访问基类public属性的成员,protected和private继承模式下,派生类对象无法访问基类的任何成员。private继承模式下,派生类的子类内部无法访问基类的任何成员

2.Is-a / Has-a / Is-implemented-in-terms-of

(1)public继承塑模出is-a关系

class Person{};
class Student : public Person{}; 
void eat(const Person& p){}
void study(const Student& s){}

Person p;
Student s;

eat(p);     //correct, p is a person
eat(s);     //correct, s is a student as well as a person

study(p);   //error,   p is not a student
study(s);   //correct, s is a student

public继承意味着"is-a"的关系,每个派生类对象同时也是基类对象,反之不成立;或者说,任何基类可以出现的地方,子类也一定可以出现(里氏代换原则)。
(2)复合

  • 概念:复合是类型之间的一种关系,当某种类型的对象内含其他种类的对象时,便是这种关系。复合意味着has-a(有一个)或 is-implemented-in-terms-of(根据某物实现出)。当复合发生于应用域内的对象(人、汽车等某些事物)之间,表现出has-a的关系;当它发生于实现域(缓冲区、互斥器等实现细节上的人工制品)内则是表现is-implemented-ni-terms-of的关系。

  • 复合表现has-a

class Address{...};
class PhoneNumber{...};
class Person{
public:
    ...
private:
    std::string name;       //合成成分物
    Address address;        //同上
    PhoneNumber voiceNumber;//同上
    PhoneNumber faxNumber;  //同上
};

上述Person class示范has-a关系。Person有一个名称,一个住址,以及语音和传真两笔电话号码。我们不会说“人是一个名称”和“人是一个地址”,而会说“人有一个名称”和“人有一个地址”。

  • 复合表现is-implemented-in-terms-of
template <typename T>
class Set{
public:
    bool member(const T& item)const;
    void insert(const T& item);
    void remove(const T& item);
    std::size_t size()const;
private:
    std::list<T> rep;
};

这里表达的意思是“set对象可根据list对象实现出来”,而不是“set对象有一个list对象”。set成员函数可大量依赖list以及标准库其他部分提供的技能来完成。

(3)private继承意味着is-implemented-in-terms-of

class Person{...};
class Student : private Person{...};

void eat(const Person& p);

Person p;
Student s;

eat(p); //correct, p is a person
eat(s); //error

从以上的例子可以看出,private继承并不意味着is-a关系。

  • 如果classes之间是private继承关系:1)编译器不会自动将一个derived class对象转换为一个base class对象;2)由private base class继承而来的所有成员,在derived class中都会变成private属性,纵使它们在base class中原本是protected或public属性。

  • private继承导致base class中的所有成员在derived class中都是private,这就意味着derived class的对象以及由derived class派生的子类都无法直接访问derived class中base class部分的成员,也就是通过derived class访问base class的接口被屏蔽了,因此,private继承意味只有实现部分被继承,借口部分应略去。

  • private继承意味is-implemented-in-terms-of, 而复合的意义也是这样。尽可能使用复合,必要时才使用private继承。当protected成员或/和virtual函数牵扯进来时,我们就该考虑private继承了。

4.EBO(empty base optimization: 空白基类最优化)
class Empty{};

class HasIntPublic : public Empty{
private:
    int x;
};

class HasIntProtected : protected Empty{
private:
    int x;
};

class HasIntPrivate : private Empty{
private:
    int x;
};

class HasIntEmpty{
private:
    int x;
    Empty e;
};

cout << "sizeof(Empty) = " << sizeof(Empty) << endl;                    //print 1
cout << "sizeof(HasIntPublic) = " << sizeof(HasIntPublic) << endl;      //print 4
cout << "sizeof(HasIntProtected) = " << sizeof(HasIntProtected) << endl;//print 4
cout << "sizeof(HasIntPrivate) = " << sizeof(HasIntPrivate) << endl;    //print 4
cout << "sizeof(HasIntEmpty) = " << sizeof(HasIntEmpty) << endl;        //print 8

(1)空白基类Empty,在现实生活中,并不真的是empty,虽然它们从未拥有non-static成员变量,却往往内含typedefs, enums, static成员变量,或non-virtual函数。前面已经讨论过, 这些成分是不占用class的内存空间的。

(2)无论哪种继承方式,当基类是类似于Empty这样的空白基类时,编译器都会执行EBO。

(3)当我们面临复合(类似于HasIntEmpty)和private继承(HasIntPrivate)之间的抉择时,很容易发现,private继承由于EBO机制而更加节省空间,而复合就没法做到这样,即使复合成分是一个Empty class的对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值