目录
一、类的自动转换类型和强制转换类型
二、继承的相关知识
(一)基本知识
(二)继承的三种方式
(三)继承关系中父子的内存大小
(四)继承中的构造函数和析构函数
一、类的自动转换类型和强制转换类型
如果我们想让类对象转换成基本类型的数据,我们需要在类中添加转换函数。
1、转换函数必须是类方法;
2、转换函数不能指定返回类型;
3、转换函数不能有参数。
#include
using namespace std;
class Mystring{
public:
//被explicit修饰的构造函数不能用于自动类型转换或者隐式类型转换
explicit Mystring(int len){
cout<<"Mystring有参构造Mystring(int len)"<
报错:
分析:因为主函数的Mystring str1=10调用的是
explicit Mystring(int len){
cout<<"Mystring有参构造Mystring(int len)"< }
这句话,因为explicit修饰的构造函数只能是int型变量,不能转换成其他形式,又因为出现10的时候不确定他是整型还是字符型,所以没办法实现转换。
但是Mystring str1 = Mystring(10);就可以确定调用的是int型的对象
解决方法:可以把explicit去掉,或者把Mystring str1 = Mystring(10);加上
二、继承的相关知识
(一)基本知识
1、继承:是面向对象的一大特征
多个类当中存在相同的属性和行为时,将这些内容抽取到一个单独的类中,那么多个类无需再定义这些属性和行为时,只要继承那个类即可。
2、继承的格式:
class 子类 : 继承方式 父类{
};
3、父类:超类,基类
子类:被称为派生类
4、继承的好处:
1)提高了代码的复用性;
2)提高了代码的维护性;
3)让类和类之间产生了关系,是多态的前提。
继承的弊端:
1)类的耦合性增加了;
2)开发的原则:高内聚,低耦合;
耦合:类和类的关系 //类和类的关系越紧密,耦合度越高;
内聚:自己完成一件事的能力 //独立的一个类完成的功能越大,内聚就越强。
#include
using namespace std;
//人类
class Person{
public:
string name; //姓名
int age; //年龄
void eat(){
cout<<"吃饭"<
(二)继承的三种方式
1、公有继承 public
2、保护继承 protected
3、私有继承 private
派生类继承基类,派生类会拥有基类中全部的成员变量和成员方法;
在派生类(子类)中,继承的成员不一定能够直接访问,不同的继承方法会导致不同的访问权限。
继承方式的实现
基类(父类)成员权限 派生类(子类)成员权限 公有 公有 公有继承 保护 保护 私有 不能访问 公有 保护 保护继承 保护 保护 私有 不能访问 公有 私有 私有继承 保护 私有 私有 不能访问
#include
using namespace std;
//基类
class Base{
public:
int a;
protected:
int b;
private:
int c;
};
//子类 公有继承
class Son1 : public Base{
public:
void func(){
a=10;//父类中的a到了子类,是public
b=20;//父类中的b到了子类,是protected
// c=30;//父类中的c到了子类,是不可访问的,会报错
}
};
//子类 保护继承
class Son2 : protected Base{
public:
void func1(){
a=10;//父类中的a到了子类,是protected
b=20;//父类中的b到了子类,是protected
// c=30;//父类中的c到了子类,是不可访问的,会报错
}
};
//子类 私有继承
class Son3 : private Base{
public:
void func2(){
a=10;//父类中的a到了子类,是private
b=20;//父类中的b到了子类,是private
// c=30;//父类中的c到了子类,是不可访问的,会报错
}
};
int main()
{
Son1 son;
son.func();
}
(三)继承关系中父子的内存大小
我们通过一个程序来说明
#include
using namespace std;
class Base{
public:
int a = 10;
void func(){
cout<<"a=10"<
分析:我们发现父类的内存大小是12,这个12是怎么的出来的呢?原来啊,一个int型占4个字节,一共有三个int型,所以是12个字节的大小。但是还有一个void func()的成员方法函数呢,就没有占据内存嘛?其实类中的成员方法和成员变量是分开存储的,在对象中,只保存了成员变量的信息。
但是我们又发现子类占据16个内存的大小,其实是子类将父类所有的成员都继承了过来,包括私有的。
(四)继承中的构造函数和析构函数
1、创建子类对象时,会先调用父类的构造函数,对父类的数据进行初始化;
2、再调用数据成员的构造函数对数据成员进行初始化;
3、然后调用子类的构造函数对子类数据进行初始化;
4、析构的顺序和构造的顺序相反
#include
using namespace std;
//基类
class Base{
public:
Base(){
cout<<"Base的构造函数"<
子类的构造函数必须使用父类的构造函数对父类数据进行初始化;
子类的构造函数会默认使用父类的默认构造函数对父类数据进行初始化;
#include
using namespace std;
class Base{
public:
int m_a;
Base(int a)
{
this->m_a=a;
cout<<"Base的有参构造函数"<m_b=b;
cout<<"son(int b)的构造函数"<
分析:1行和2行的内容是由son s1调用的;3行和4行的内容是由son s(20)调用的;5行的内容是通过子类给父类进行初始化;6行的内容是子类自己初始化;7行的内容是析构的内容,正好跟构造函数的内容相反。
如果我们想让类对象转换成基本类型的数据,我们需要在类中添加转换函数。
1、转换函数必须是类方法;
2、转换函数不能指定返回类型;
3、转换函数不能有参数。
报错:
分析:因为主函数的Mystring str1=10调用的是
explicit Mystring(int len){
cout<<"Mystring有参构造Mystring(int len)"<} 这句话,因为explicit修饰的构造函数只能是int型变量,不能转换成其他形式,又因为出现10的时候不确定他是整型还是字符型,所以没办法实现转换。
但是Mystring str1 = Mystring(10);就可以确定调用的是int型的对象
解决方法:可以把explicit去掉,或者把Mystring str1 = Mystring(10);加上
二、继承的相关知识
(一)基本知识
1、继承:是面向对象的一大特征
多个类当中存在相同的属性和行为时,将这些内容抽取到一个单独的类中,那么多个类无需再定义这些属性和行为时,只要继承那个类即可。
2、继承的格式:
class 子类 : 继承方式 父类{
};
3、父类:超类,基类
子类:被称为派生类
4、继承的好处:
1)提高了代码的复用性;
2)提高了代码的维护性;
3)让类和类之间产生了关系,是多态的前提。
继承的弊端:
1)类的耦合性增加了;
2)开发的原则:高内聚,低耦合;
耦合:类和类的关系 //类和类的关系越紧密,耦合度越高;
内聚:自己完成一件事的能力 //独立的一个类完成的功能越大,内聚就越强。
#include
using namespace std;
//人类
class Person{
public:
string name; //姓名
int age; //年龄
void eat(){
cout<<"吃饭"<
(二)继承的三种方式
1、公有继承 public
2、保护继承 protected
3、私有继承 private
派生类继承基类,派生类会拥有基类中全部的成员变量和成员方法;
在派生类(子类)中,继承的成员不一定能够直接访问,不同的继承方法会导致不同的访问权限。
继承方式的实现
基类(父类)成员权限 派生类(子类)成员权限 公有 公有 公有继承 保护 保护 私有 不能访问 公有 保护 保护继承 保护 保护 私有 不能访问 公有 私有 私有继承 保护 私有 私有 不能访问
#include
using namespace std;
//基类
class Base{
public:
int a;
protected:
int b;
private:
int c;
};
//子类 公有继承
class Son1 : public Base{
public:
void func(){
a=10;//父类中的a到了子类,是public
b=20;//父类中的b到了子类,是protected
// c=30;//父类中的c到了子类,是不可访问的,会报错
}
};
//子类 保护继承
class Son2 : protected Base{
public:
void func1(){
a=10;//父类中的a到了子类,是protected
b=20;//父类中的b到了子类,是protected
// c=30;//父类中的c到了子类,是不可访问的,会报错
}
};
//子类 私有继承
class Son3 : private Base{
public:
void func2(){
a=10;//父类中的a到了子类,是private
b=20;//父类中的b到了子类,是private
// c=30;//父类中的c到了子类,是不可访问的,会报错
}
};
int main()
{
Son1 son;
son.func();
}
(三)继承关系中父子的内存大小
我们通过一个程序来说明
#include
using namespace std;
class Base{
public:
int a = 10;
void func(){
cout<<"a=10"<
分析:我们发现父类的内存大小是12,这个12是怎么的出来的呢?原来啊,一个int型占4个字节,一共有三个int型,所以是12个字节的大小。但是还有一个void func()的成员方法函数呢,就没有占据内存嘛?其实类中的成员方法和成员变量是分开存储的,在对象中,只保存了成员变量的信息。
但是我们又发现子类占据16个内存的大小,其实是子类将父类所有的成员都继承了过来,包括私有的。
(四)继承中的构造函数和析构函数
1、创建子类对象时,会先调用父类的构造函数,对父类的数据进行初始化;
2、再调用数据成员的构造函数对数据成员进行初始化;
3、然后调用子类的构造函数对子类数据进行初始化;
4、析构的顺序和构造的顺序相反
#include
using namespace std;
//基类
class Base{
public:
Base(){
cout<<"Base的构造函数"<
子类的构造函数必须使用父类的构造函数对父类数据进行初始化;
子类的构造函数会默认使用父类的默认构造函数对父类数据进行初始化;
#include
using namespace std;
class Base{
public:
int m_a;
Base(int a)
{
this->m_a=a;
cout<<"Base的有参构造函数"<m_b=b;
cout<<"son(int b)的构造函数"<
分析:1行和2行的内容是由son s1调用的;3行和4行的内容是由son s(20)调用的;5行的内容是通过子类给父类进行初始化;6行的内容是子类自己初始化;7行的内容是析构的内容,正好跟构造函数的内容相反。
1、继承:是面向对象的一大特征
多个类当中存在相同的属性和行为时,将这些内容抽取到一个单独的类中,那么多个类无需再定义这些属性和行为时,只要继承那个类即可。
2、继承的格式:
class 子类 : 继承方式 父类{
};
3、父类:超类,基类
子类:被称为派生类
4、继承的好处:
1)提高了代码的复用性;
2)提高了代码的维护性;
3)让类和类之间产生了关系,是多态的前提。
继承的弊端:
1)类的耦合性增加了;
2)开发的原则:高内聚,低耦合;
耦合:类和类的关系 //类和类的关系越紧密,耦合度越高;
内聚:自己完成一件事的能力 //独立的一个类完成的功能越大,内聚就越强。
#includeusing namespace std; //人类 class Person{ public: string name; //姓名 int age; //年龄 void eat(){ cout<<"吃饭"< (二)继承的三种方式
1、公有继承 public
2、保护继承 protected
3、私有继承 private
派生类继承基类,派生类会拥有基类中全部的成员变量和成员方法;
在派生类(子类)中,继承的成员不一定能够直接访问,不同的继承方法会导致不同的访问权限。
继承方式的实现 基类(父类)成员权限 派生类(子类)成员权限 公有 公有 公有继承 保护 保护 私有 不能访问 公有 保护 保护继承 保护 保护 私有 不能访问 公有 私有 私有继承 保护 私有 私有 不能访问 #includeusing namespace std; //基类 class Base{ public: int a; protected: int b; private: int c; }; //子类 公有继承 class Son1 : public Base{ public: void func(){ a=10;//父类中的a到了子类,是public b=20;//父类中的b到了子类,是protected // c=30;//父类中的c到了子类,是不可访问的,会报错 } }; //子类 保护继承 class Son2 : protected Base{ public: void func1(){ a=10;//父类中的a到了子类,是protected b=20;//父类中的b到了子类,是protected // c=30;//父类中的c到了子类,是不可访问的,会报错 } }; //子类 私有继承 class Son3 : private Base{ public: void func2(){ a=10;//父类中的a到了子类,是private b=20;//父类中的b到了子类,是private // c=30;//父类中的c到了子类,是不可访问的,会报错 } }; int main() { Son1 son; son.func(); } (三)继承关系中父子的内存大小
我们通过一个程序来说明
#includeusing namespace std; class Base{ public: int a = 10; void func(){ cout<<"a=10"< 分析:我们发现父类的内存大小是12,这个12是怎么的出来的呢?原来啊,一个int型占4个字节,一共有三个int型,所以是12个字节的大小。但是还有一个void func()的成员方法函数呢,就没有占据内存嘛?其实类中的成员方法和成员变量是分开存储的,在对象中,只保存了成员变量的信息。
但是我们又发现子类占据16个内存的大小,其实是子类将父类所有的成员都继承了过来,包括私有的。
(四)继承中的构造函数和析构函数
1、创建子类对象时,会先调用父类的构造函数,对父类的数据进行初始化;
2、再调用数据成员的构造函数对数据成员进行初始化;
3、然后调用子类的构造函数对子类数据进行初始化;
4、析构的顺序和构造的顺序相反
#includeusing namespace std; //基类 class Base{ public: Base(){ cout<<"Base的构造函数"< 子类的构造函数必须使用父类的构造函数对父类数据进行初始化;
子类的构造函数会默认使用父类的默认构造函数对父类数据进行初始化;
#includeusing namespace std; class Base{ public: int m_a; Base(int a) { this->m_a=a; cout<<"Base的有参构造函数"< m_b=b; cout<<"son(int b)的构造函数"< 分析:1行和2行的内容是由son s1调用的;3行和4行的内容是由son s(20)调用的;5行的内容是通过子类给父类进行初始化;6行的内容是子类自己初始化;7行的内容是析构的内容,正好跟构造函数的内容相反。



