1. 简述继承
class 子类 : 继承权限 父类
class Animal {
public :
string name() { return this->__name; }
private :
string __name;
};
class Cat : public Animal {
};
- 继承父类的所有成员属性和方法,涉及到相关的访问控制权限
- 子类拥有父类成员,但是不代表子类能访问这些成员
2.子类的访问权限
继承权限究竟意味着什么?子类能够访问到父类的哪些成员属性和成员方法?
子类之于父类是父类的类外,无论什么继承权限,在子类中都只能访问到父类的 public 和 protected 权限的成员。
注意:在子类外声明的子类对象属于子类类外,是否能访问子类中继承自父类的成员,就要看“对外的访问属性”。
继承权限(横) 属性在基类中的权限(竖) | public | protected | private |
---|
public | ? | ? | ? | protected | ? | ? | ? | private | ? | ? | ? |
表中横竖两栏的交叉点表示子类能否访问父类中该权限的成员。
子类的访问权限与继承权限无关,只能访问public和protected权限的成员
3. 对外的访问权限
假设类Base 中有个属性 a ,子类Sub 继承自 Base 类,外部能否看到 Sub 类中的属性 a ,取决于类 Base 中属性 a 的访问权限和子类Sub 继承 Base 的继承权限。
“继承权限"影响类外访问子类内继承自父类的属性的"访问权限”
继承权限(横) 属性在基类中的权限(竖) | public | protected | private |
---|
public | public | protected | private | protected | protected | protected | private | private | ? | ? | ? |
两栏交叉位置就是子类中继承自父类的属性的对外访问权限,上表表现的就是取两个权限中权限较低的。
对
外
的
访
问
权
限
=
m
i
n
(
子
类
继
承
权
限
,
基
类
中
属
性
的
访
问
权
限
)
对外的访问权限 = min(子类继承权限,基类中属性的访问权限)
对外的访问权限=min(子类继承权限,基类中属性的访问权限)
4. 代码测试
4.1 父类对象和子类对象的大小
#include <iostream>
using namespace std;
class Animal {
public :
Animal() = default;
Animal(string name) : name(name) {}
void say() {
cout << "My name is " << name << endl;
}
private :
string name;
};
class Cat : public Animal {};
int main() {
cout << sizeof(Animal) << " " << sizeof(Cat) << endl;
return 0;
}
运行结果:
24 24
对象的大小只和属性有关,Cat 对象和 Animal 对象大小完全相同,因为 Cat 类继承自 Animal 类,所以继承了 Animal 类中的所有属性。
4.2 不同的继承权限
1、Cat 私有继承 Animal,Tiger 公有继承 Cat
#include <iostream>
using namespace std;
class Animal {
public :
Animal(string name = "mimi") : name(name) {}
void say() {
cout << "My name is " << name << endl;
}
protected :
string name;
};
class Cat : private Animal {
public :
void say1() {
cout << "miaomiaomiao, my name is " << name << endl;
}
};
class Tiger : public Cat {
public :
void say2() {
cout << "houhouhou, my name is " << name << endl;
}
};
int main() {
cout << sizeof(Animal) << " " << sizeof(Cat) << endl;
Cat c;
c.say1();
return 0;
}
编译出错:
Cat.cpp:31:45: error: 'name' is a private member of 'Animal'
cout << "houhouhou, my name is " << name << endl;
^
Cat.cpp:21:13: note: constrained by private inheritance here
class Cat : private Animal {
^~~~~~~~~~~~~~
Cat.cpp:18:12: note: member is declared here
string name;
^
1 error generated.
错误原因:Cat 因为继承自 Animal,它拥有了父类的 name 属性,因为是私有继承自父类,所以 Cat 类中的 name 属性的访问权限是 private,而 Tiger 是 Cat 的子类,子类无法访问到父类的私有成员。
2、Cat 继承 Animal 的继承权限为 protected
#include <iostream>
using namespace std;
class Animal {
public :
Animal(string name = "mimi") : name(name) {}
void say() {
cout << "My name is " << name << endl;
}
protected :
string name;
};
class Cat : protected Animal {
public :
void say1() {
cout << "miaomiaomiao, my name is " << name << endl;
}
};
class Tiger : public Cat {
public :
void say2() {
cout << "houhouhou, my name is " << name << endl;
}
};
int main() {
cout << sizeof(Animal) << " " << sizeof(Cat) << endl;
Cat c;
c.say1();
return 0;
}
可成功编译,因为 name 属性无论是在 Animal 类中还是 Cat 类中对外的访问权限都是 protected,Tiger 作为 Cat 的子类,可以访问父类的 protected 属性。
3、Cat 公有继承 Animal,Tiger 公有继承 Cat
#include <iostream>
using namespace std;
class Animal {
public :
Animal(string name = "mimi") : name(name) {}
void say() {
cout << "My name is " << name << endl;
}
protected :
string name;
};
class Cat : public Animal {
public :
void say1() {
cout << "miaomiaomiao, my name is " << name << endl;
}
};
class Tiger : public Cat {
public :
void say2() {
cout << "houhouhou, my name is " << name << endl;
}
};
int main() {
cout << sizeof(Animal) << " " << sizeof(Cat) << endl;
Cat c;
c.say1();
Animal *p = &c;
p->say();
return 0;
}
运行结果:
24 24
miaomiaomiao, my name is mimi
My name is mimi
4、修改为 protected / private 继承
#include <iostream>
using namespace std;
class Animal {
public :
Animal(string name = "mimi") : name(name) {}
void say() {
cout << "My name is " << name << endl;
}
void rename(string name) {
this->name = name;
}
protected :
string name;
};
class Cat : private Animal {
public :
void say1() {
cout << "miaomiaomiao, my name is " << name << endl;
}
};
int main() {
cout << sizeof(Animal) << " " << sizeof(Cat) << endl;
Cat c;
c.say1();
Animal *p = &c;
p->say();
return 0;
}
编译出错:
Cat.cpp:43:17: error: cannot cast 'Cat' to its private base class 'Animal'
Animal *p = &c;
^
Cat.cpp:24:13: note: declared private here
class Cat : private Animal {
^~~~~~~~~~~~~~
1 error generated.
出错原因:子类对象隐式转换为父类指针时出现错误,只要是 private 或 protected 继承,子类的对象就无法转换为父类的地址。
【理解:不希望外界访问到父类中的所有属性和方法,为了达到这个目的,所以使用了私有继承。而子类地址转换为父类地址的操作可能使得外界能访问到父类的属性和方法,所以为了避免这种情况,就彻底不让进行地址转换。protected 继承同理。】
|