面向对象和面向过程
面向对象:划分事务参与的对象,关注对象的交互,现实关系更真实的模拟现实
面向对象三大特性:封装,继承,多态
封装:私有,公有,为了更好的管理
c语言数据,方法分离,c++没有分离都定义在类中。
面向过程:把一项事务分为各步完成
类
struct 关键字可以作为结构体,又能作为类
类中可以定义成员函数和成员变量
struct a
{
void add(int a, int b)//成员函数
{
return a+b;
}
int a;//成员变量
}
int main()
{
stack a;
a.add(1,2);
}
class作为类的关键字可以替代struct,两者区别,如果class默认访问权限private,struct默认访问权限public,访问限定符只在编译时有用,映射到内存时无区别。
类的访问权限问题
C++封装方式:用类将对象的属性与方法结合在一起,让对象更加完善,通过访问权限选择性将其接口提供给外部用户使用
公有在类外面可以直接访问,保护和私有不行,后两者区别在继承中体现。
struct a
{
public:
void add(int a, int b)//成员函数
{
return a+b;
}
private:
int _a;//成员变量,一般用_前
}
//在函数外面不能访问 _a,函数里面的指针可以
在下一个限定符(private)之前都是上一个限定符的范围public(公有)
类可以声明定义分离,在类中定义函数默认内联函数,长函数一般是在类中声明,短函数在类里面定义。
//头文件
class A
{
void add(int a, int b);
}
//源文件
void A::add(int a,int b)
{
return a+b;
}
域分为局部,类,全局,局部,全局影响生命周期,类域不影响生命周期。
类的大小:
类里面的变量是声明,不占空间,类实例化,才开辟空间。类只能一整个整体定义,不能单调定义类中的一个变量。
类的大小只和成员变量有关,和成员变量无关。
类的成员函数放在公共地方,创建多个实例时,不会拷贝多份函数代码,会创建多个成员变量。
大小计算规则:和struct结构体一样
struct A{
int add(int a,int b)
{
return a+b;
}
int _a;
int _b;
};
sizeof(A)//8
*类可以不写关键字struct。
没有对象的类也有空间 占1byte
struct A
{
int add(int a,int b)
{
return a+b;
}
};
sizeof(A);//1
实例调用会有this指针,隐性传递过去给函数
struct A
{
int add(int a,int b)
{
return a+b;
}
};
A a;
a.add(a,b);
实例a调用时,除了传递a,b参数还传了this指针this指针,指向实例a。前面我们说过函数成员是放在一个公有的地方,所以为了分辨不同的实例,要传指向实例的指针进入是很合理的。
this 指针不能在类外调用,显性传递,但能在类中调用,访问成员变量函数
struct A
{
int add(int a,int b)
{
return a+b+this.c;
}
int _c=0;
};
A a;
a.add(a,b);
感觉和python的self很像。
类当中的默认成员函数:
构造函数:初始化实例
struct A
{
A(int c)
{
_c = c;
}//构造函数
int add(int a, int b)
{
return a + b;
}
int _c;
};
A a(1);//构造函数调用
函数名与类名相同,无返回值,不用 void 。
对象实例化编辑器会自动调用。
C11:支持成员变量缺省值
struct A
{
int _c=1;//成员声明给缺省数,不是初始化
};
全缺省构造函数和无参构造会有在函数调用时歧义。虽然两个函数可以重载,但是都可以无参调用,会有歧义。
struct A
{
A()
{
_c =1;
}
A(int c =1)
{
_c =c;
}
int _c;
};
当类无构造函数时,会自动生成:
1.内置数据类型:不处理,有些编译器可能会处理
2.自定义数据类型:class,struct 会使用它的构造函数
内置数据类型给缺省值,成员变量全是自定义数据类型不用写构造函数。
析构函数:释放空间等,,如malloc 开辟的空间。
析构函数在类名加-。
无参数,无返回值。一个类会有一个析构函数,如果无显示定义,会自动生成一个。析构不能重载,内置数据类型不处理,自定义数据类型会调用对应的析构函数。
struct A
{
int* _a;
A()//构造函数
{
_a=(int*)malloc(sizeof(int));
}
~A()//析构函数
{
free(_a);
_a=NULL;
}
};
拷贝构造函数:拷贝和复制类。
struct A
{
int* _a;
int _b=1;
A()//构造函数
{
_a=(int*)malloc(sizeof(int));
}
A(const A& d)//拷贝构造函数
{
_d=(int*)malloc(sizeof(int));//深拷贝
_b=d._b;//浅拷贝
}
~A()//析构函数
{
free(_a);
_a=NULL;
}
};
当自定义类型作为参数时,会先在类中调用拷贝构造,再运行,而内置数据类型是直接拷贝。
A c;
fun(c);
int d = 0;
fun(d);
fun(d)时会直接拷贝d,fun(c)时会先运行A(const A& d)再进入函数。
A(const A& d)
{
_d=(int*)malloc(sizeof(int));//深拷贝
_b=d._b;//浅拷贝
}
拷贝构造的参数只有一个且必须是类对象引用。用传值方式编译器会无穷递归。
传值调用就又变成参数是自定义类型,又会调用拷贝函数。
为了防止顺序弄反,可以用const修饰参数。
不定义会默认生成拷贝构造函数
1.内置类型成员:值拷贝
2.自定义类型:调用他的拷贝
因为默认情况下是值拷贝,如果_a也是值拷贝的话就会变成两个变量指向一个空间,不符合我们的想法。为了解决这个问题才有了拷贝构造的存在。