将圆的周长封装为Circle类,里面有访问权限、属性(成员变量)和行为(成员方法),类的属性和行为统称为成员。在主函数中实例化、给属性赋值,使用行为。
#define PI 3.14
class Circle {
//访问权限
public:
//属性
int r;
//行为
double c() {
return 2 * PI * r;
}
};
void main() {
//实例化
Circle c1;
c1.r = 10;
cout << "周长:" << c1.c() << endl;;
}
访问权限类型:
1、public 公共权限 成员,类内外都可访问
2、protected 保护权限 成员,类内可以访问,类外不可以访问,子类可以访问父类的保护内容。
3、private 私有权限 成员,类内可以访问,类外不可以访问,子类不可以访问父类的私有内容。
1、默认权限不同,class默认私有private权限,struct默认public公共权限。
1、自己控制读写权限
2、对写可以检测数据有效性
class Student {
//访问权限
private:
int id=1;
int age;
string name;
public:
//行为
void func() {
cout << "Id:" << id << "\tName:" << name << "\tage:" << age << endl;
}
void SetName(string _name) {
name = _name;
}
string GetName() {
return name;
}
int GetId() {
return id;
}
void SetAge(int _age) {
if (_age < 0 || _age>150) {
age=18;
}
else {
age = _age;
}
}
};
void main() {
//实例化
Student s1;
s1.SetAge(155);
s1.SetName("张三");
s1.func();
}
3、在一个类中可以在另一个类中包含。
编译器自动调用。
主要在创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。
语法:类名(){}
1)构造函数没有返回值不写void
2)函数名称与类名相同
3)可以有参数,可以发生重载
4)程序在调用对象时会自动调用构造,无须手动调用,而且只会调用一次。
1)按参数分:有参构造和无参构造(默认)
2)按类型分:普通构造和拷贝构造
class Student {
public:
int age;
//构造函数
Student() {
cout << "默认构造函数" << endl;
}
Student(int a) {
age = a;
cout << "构造函数有参" << endl;
}
//拷贝构造
Student(const Student& p) {
//将传入的所具有的所有属性,拷贝过来
age = p.age;
cout << "拷贝构造函数" << endl;
}
};
void test01() {
//括号法
Student p1;//默认构造函数
Student p2(10);//有参
Student p3(p2);//拷贝
cout << "p2的age:" << p2.age << endl;
cout << "p3的age:" << p3.age << endl;
//显示法
Student p1;//默认构造函数
Student p2=Student(10);//有参
Student p3 = Student(p2);//拷贝
Student(10);//匿名对象,当前行执行结束后,系统会立即回收
//隐式转换法
Student p4 = 10;//有参 Student p4=Student(10)
Student p5 = p4;//拷贝
}
void main() {
test01();
}
注意:
1.调用默认构造时不加(),加()会被认为时一个函数的声明。
2.Student(10);
//匿名对象,当前行执行结束后,系统会立即回收.
3.不使用拷贝构造函数,初始化匿名对象,否则会被认为是对象的声明。
1.使用一个已创建完毕的对象来初始化一个新对象。
2.值传递的方式给函数参数传值。
3.值方式返回局部对象。
默认情况下,c++编译器至少给一个类添加3个函数
1.3.1默认构造函数(无参,函数体为空)
1.3.2默认析构函数(无参,函数体为空)
1.3.3默认拷贝构造函数,对属性进行值拷贝
调用规则:
如果用户定义有参构造函数,c++不会提供默认无参构造,但是会提供默认拷贝构造。
如果用户定义拷贝构造函数,c++不会再提供其他构造函数。
1.4.1浅拷贝(==)使用同一块内存的问题
class Student {
public:
int age;
int* h;
//构造函数
Student() {
cout << "默认构造函数" << endl;
}
Student(int a,int _h) {
age = a;
h = new int(_h);
cout << "构造函数有参" << endl;
}
拷贝构造(浅拷贝)
Student(const Student& p) {
age = p.age;
h = p.h;
cout << "拷贝构造函数" << endl;
}
//析构函数
~Student()
{
//将堆区开辟的数据做释放操作
if (h != NULL) {
delete h;
h = NULL;
}
cout << "析构函数" << endl;
}
};
void test01() {
Student p(18,180);
cout << "p2的年龄:" << p.age << "p2的身高:" << *p.h << endl;
Student p2(p);
cout << "p2的年龄:" << p2.age << "p2的身高:" << *p2.h << endl;
}
浅拷贝的问题用深拷贝(重新创建一个空间)解决
//深拷贝
Student(const Student& p) {
age = p.age;
//再创建一个空间
h = new int(*p.h);
cout << "拷贝构造函数" << endl;
}
语法:构造函数():属性1(值1),属性2(值2)...{}
Student(int a, int _h, int _c):age(a),h(_h),c(_c){
}
类中的成员可以是另一个类的对象,称该成员为对象成员。
当其他类对象作为本类成员,先构造其他,再构造自身。
析构的顺序与构造相反
class A {
public:
int a;
A(int _a) {
a = _a;
cout << "A" << endl;
}
~A() {
cout << "A析构函数" << endl;
}
};
class Student {
public:
int age;
A b;
Student(int _age, int _a):age(_age),b(_a){
cout << "Student" << endl;
}
//析构函数
~Student()
{
cout << "Student析构函数" << endl;
}
};
void test01() {
Student p( 180, 12);
cout << "age=" << p.age << ",a=" << p.b.a << endl;
}
void main() {
test01();
system("pause");
}
主要在对象销毁前系统自动调用,执行一些清理工作。
语法:~类名(){}
1)析构函数,没有返回值也不写void
2)函数名称与类名相同,在名称前要加上符号~
3)不可以有参数,不可以发生重载
4)程序在对象销毁时会自动调用析构,无须手动调用,而且只会调用一次。
class Student {
public:
//构造函数
Student() {
cout << "构造函数" << endl;
}
//析构函数
~Student()
{
cout << "析构函数" << endl;
}
};
void test01() {
Student p;//在栈上的数据,此函数执行完毕后,释放该对象。
}
void main() {
test01();
}
构造和析构都是必须的,不自己写编译器会提供一个空函数。在程序执行结束后会调。
就是在成员变量和成员函数前加上static
1、静态成员变量(不属于某个对象):
所有对象共享一份数据
在编译阶段分配内存
类内声明,类外初始化
可通过对象或者类名进行访问,也有访问权限。
class Student {
public:
//类内声明
static int age;
private://类外访问不到
static int b;
};
//类外初始化
int Student:: age=100;
int Student::b = 100;
void test01() {
Student s;
//通过对象访问
cout << s.age << endl;
Student s1;
s1.age = 200;
//通过类名访问
cout << Student::age << endl;
}
void main() {
test01();
system("pause");
}
2、静态成员函数:
所有对象共享同一个函数
静态成员函数只能访问静态成员变量
class Student {
public:
//类内声明
static int age;
int b;
static void func() {
age = 300;
b = 400;//报错,非静态变量,无法区别调用
cout << "111111func" << endl;
}
//析构函数
~Student()
{
cout << "Student析构函数" << endl;
}
private://类外访问不到
static int b;
static void func2() {
cout << "2222222func" << endl;
}
};
//类外初始化
int Student:: age=100;
int Student::b = 100;
void test02() {
//通过对象访问
Student s2;
s2.func();
//通过类名访问
Student::func();
}
成员变量和成员函数分开存储
指向被调用的成员函数所属的对象
this指针隐含每一个非静态成员函数内的一种指针,不需要定义,直接使用。
用途:当形参和成员变量同名时,用this指针区分。在类的非静态成员函数中返回对象本身,可用return *this
class student {
public:
int a;
student(int a) {
this->a = a;
}
//student&不会创建一个新的对象,student会创建一个新得对象
student& A(student& p) {
this->a = this->a + p.a;
//this指向s1的指针,而*this指向的s1的本体
return *this;
}
};
void main() {
student s(10);
student s1(10);
//链式编程思想,可以无限追加
s.A(s1).A(s1).A(s1);
cout << "a=" << s.a << endl;
system("pause");
}
空指针可以调用成员函数,但要注意有没有用到this指针,如果用到,需判断保证代码的健壮性。
public:
int a;
void show() {
cout << "this is student class" << endl;
}
void showA() {
//判断保证代码的健壮性,防止崩溃
if (this == NULL) {
return;
}
cout << "a=" << this->a << endl;
}
};
void main() {
student* s=NULL;
s->show();
s->showA();
system("pause");
}
1、常函数:
成员函数后加const后称这个函数为常函数
常函数内不可以修改成员属性
成员属性声明时加关键字mutable后,在常函数中依然可以修改
2、常对象:
声明对象前加const称该对象为常对象
常对象只能调用常对象
class student {
public:
int a;
mutable int b;//特殊变量,即使在常函数中也可以修改这个值
//this指针的本质是指针常量,指针指向不可以修改
//相当于const student * const this
//在成员函数后面加const修饰的是this指向,让指针指向的值不可修改
void show()const {
a = 100;//报错
this = NULL;//报错
b = 1111;//不报错
cout << "this is student class" << endl;
}
void showA() {
}
};
//常对象
void test() {
const student s1;
s1.a = 100;//报错
s1.b = 1000;//不报错
//常函数只能掉常对象
s1.show();//不报错
s1.showA();//报错
}
void main() {
student* s=NULL;
s->show();
s->showA();
system("pause");
}