将属性和行为作为一个整体,表现生活中的物体:
//设计一个圆类:
const double PI = 3.14;
class circle{
//访问权限
public:
//属性
//半径
int m_r;
//行为
//获取周长
double calZC(){
return 2*PI*m_r;
}
};
int main(){
circle c1; //实例化:通过一个类创建一个对象;
c1.m_r = 10;
cout << "圆的周长为:" << c1.calZC() << endl;
return 0;
}
公共权限 public:成员 类内可以访问,类外也可以访问。
保护权限 protected:成员 类内可以访问,类外不可以访问。儿子可以访问父亲中的保护内容。
私有权限 private:成员 类内可以访问,类外不可以访问。儿子不可以访问父亲中的私有内容。
class person{
public:
string name;
protected:
string car;
private:
int password;
public:
void func(){
name = "alex";
car = "benz";
password = 123456;
}
};
int main(){
person p1;
p1.name = "Bob";
//p1.car = "bycicle"; //错误
//p1.password = 123; //错误
return 0;
}
class和struct的唯一区别:默认访问权限不同。class默认为私有private,struct默认为公有public。
优点1:可以自己控制读写权限;
优点2:对于写权限,我们可以检测数据的有效性。
class person{
private:
string name; //可读可写
int age; //可读可写有限制
string lover; //只写
public:
void setname(string str){
name = str;
}
string setname(){
return name;
}
int getage(){
return age;
}
void setage(int n){
if(age<0 || age>150){
age = 0;
cout << "error" << endl;
return;
}
age = n;
}
void setlover(string str){
lover = str;
}
};
int main(){
person p;
p.setname("alex");
cout << p.getname() << endl;
return 0;
}
Point.h:
class Point{
private:
int m_x;
int m_y;
public:
void setx(int x);
int getx();
void sety(int y);
int gety();
};
Point.cpp:
#include "Point.h"
void Point::setx(int x){
m_x = x;
}
int Point::getx(){
return m_x;
}
......
......
int main(){
return 0;
}
构造函数和析构函数由编译器提供。
构造函数:类名(){}
析构函数:~类名(){}
class person{
public:
person(){
cout << 1 << endl;
}
~person(){
cout << 2 << endl;
}
};
void test(){
person p1;
}
int main(){
test(); //会输出1和2;
person p2; //只输出1;
return 0;
}
两种分类方式:
三种调用方式:
class person{
public:
//普通无参构造
person(){
//cout << 1 << endl;
}
//普通有参构造
person(int a){
m_age = a;
//cout << 1 << endl;
}
//拷贝构造
person(const person &p){
m_age = p.m_age;
}
private:
int m_age;
};
//调用方式:
void test(){
//括号法
person p1; //调用普通无参构造,不要加小括号;
person p2(10); //调用普通有参构造;
person p3(p2); //调用拷贝构造;
//显示法
person p1;
person p2 = person(10);
person p3 = person(p2);
//person(10)和person(p2)是匿名对象,当前行结束后自动回收;
//隐式转换法
person p4 = 10;
person p5 = p4;
}
int main(){
return 0;
}
class person{
public:
//普通无参构造
person(){
//cout << 1 << endl;
}
//普通有参构造
person(int a){
m_age = a;
//cout << 1 << endl;
}
//拷贝构造
person(const person &p){
m_age = p.m_age;
}
private:
int m_age;
};
void test(){
person p1(20);
person p2(p1);
}
int main(){
test();
return 0;
}
如果用户定义有参构造函数,C++不再提供默认无参构造,但是会提供默认拷贝构造;
如果用户定义拷贝构造函数,C++不会再提供其他构造函数。
浅拷贝:简单的赋值拷贝操作。
深拷贝:在堆区重新申请空间,进行拷贝操作。
如果在类内使用new在堆区申请了空间,要在析构函数内使用delete手动释放空间。
浅拷贝的问题:堆区内存重复释放。
解决办法:使用深拷贝。
class person{
public:
//深拷贝
person(const person &p){
m_age = p.m_age;
m_height = new int(*p.m_height);
}
//析构函数
~person(){
if(m_height!=NULL){
delete m_height;
m_height = NULL;
}
}
private:
int m_age;
int *m_height;
};
C++提供了初始化列表语法,用于初始化属性:
class person{
public:
//传统初始化操作:
//person(int a, int b, int c){
// m_a = a;
// m_b = b;
// m_c = c;
//}
//初始化列表:
person(int a, int b, int c):m_a(a), m_b(b), m_c(c){}
int m_a;
int m_b;
int m_c;
};
void test(){
person p1(1,2,3);
}
int main(){
test();
return 0;
}
class phone{
public:
phone(string name){
m_name = name;
}
string m_name;
};
class person{
public:
person(string name, phone ph):m_name(name), m_phone(ph){}
string m_name;
phone m_phone;
};
void test(){
person p1("alex", "iphone");
}
int main(){
test();
return 0;
}
构造时先构造phone,再构造person;析构时相反。
静态成员就是在成员变量和成员函数之前加上关键字static,称为静态成员。
静态成员分为静态成员变量和静态成员函数:
所有对象共享同一份数据;
在编译阶段分配内存;
类内声明,类外初始化。
class person{
public:
static int m_a; //静态成员变量,类内声明
private:
statci int m_b;
};
int person::m_a = 100; //类外初始化
int person::m_b = 200;
void test(){
person p;
cout << p.m_a << endl; //输出100
person p2;
p2.m_a = 200;
cout << p.m_a << endl; //输出200,因为m_a是共享的
}
void test2(){
//静态成员变量有两种访问方式:
//1.通过对象进行访问:
person p;
cout << p.m_a << endl;
//2.通过类名进行访问:
cout << person::m_a << endl;
}
void test3(){
cout << person::m_b << endl; //错误,静态成员变量也有访问权限
}
int main(){
test();
return 0;
}
所有对象共享同一个函数;
静态成员函数只能访问静态成员变量。
class person{
public:
static void func(){
m_a = 100;
//m_b = 200; //报错,因为静态成员函数只能访问静态成员变量
cout << 1 << endl;
}
static int m_a;
int m_b;
};
//静态成员函数的两种访问方式:
void test(){
//1.通过对象访问:
person p;
p.func();
//2.通过类名访问:
person::func();
}
int main(){
test();
return 0;
}
只有非静态成员变量才属于类的对象。
class person{
public:
int m_a;
static int m_b;
void func(){}
};
//静态成员函数的两种访问方式:
void test(){
person p;
cout << sizeof(p) << endl;
//空对象占用的内存空间为1,有1个int变量的对象占用的内存空间为4,加成员函数或静态成员变量不影响对象占用的内存空间。
}
int main(){
test();
return 0;
}
this指针不需要定义,可以直接使用。
用途:
当形参和成员变量同名时,可用this指针来区分;
在类的非静态成员函数中返回对象本身时,可使用return *this。
class person{
public:
person(int age){
//age = age; //这样写发生了混淆
//方法一,不用同样的名称
//方法二:
//this指针指向 被调用的成员函数 所属的对象
this->age = age;
}
person& add(person &p){
this->age += p.age;
return *this;
}
int age;
};
void test(){
person p1(18);
cout << p1.age << endl;
}
void test2(){
person p2(10);
p2.add(p1).add(p1).add(p1).add(p1); //链式编程
cout << p2.age << endl;
}
int main(){
test();
test2();
return 0;
}
class person{
public:
void show(){
cout << 1 << endl;
}
void showage(){
if(this==NULL){ //防止传入空指针导致出错;
return;
}
cout << m_age << endl;
}
int m_age;
};
void test(){
person *p = NULL;
p->show(); //正确
//p->showage(); //错误
}
int main(){
test();
return 0;
}
常函数和常对象:
class person{
public:
//this指针的本质是指针常量,指针的指向是不可以修改的,但指向的值是可以修改的。
//常函数:
void change() const{ //这个const使指向的值也不可修改了
m_a = 200; //错误
m_b = 100; //正确,因为m_b是mutable变量
}
void func(){
;
}
int m_a;
mutable int m_b;
};
void test(){
//常对象:
const person p1();
p1.m_a = 100; //错误
p1.m_b = 200; //正确
//常对象只能调用常函数,因为普通成员函数可以修改属性:
p1.func(); //错误
p1.change(); //正确
}
int main(){
test();
return 0;
}
友元的目的是让一个函数或者类,能够访问另一个类的私有成员。
class building{
friend void goodfriend(building *b1);
public:
building(){
m_sittingroom = "客厅";
m_bedroom = "卧室";
}
string m_sittingroom;
private:
string m_bedroom;
};
//全局函数做友元:
void goodfriend(building *b1){
cout << b1->m_sittingroom << endl; //一直可以访问;
cout << b1->m_bedroom << endl; //不能直接访问,除非使用friend;
}
int main(){
building b1;
goodfriend(&b1);
return 0;
}
class building{
friend class goodfriend; //第二行
public:
building();
string m_sittingroom;
private:
string m_bedroom;
};
//类外写成员函数:
building::building(){
m_sittingroom = "客厅";
m_bedroom = "卧室";
}
class goodfriend(){
public:
goodfriend();
void visit();
building *b;
};
goodfriend::goodfriend(){
b = new building;
}
void goodfriend::visit(){
cout << b->m_sittingroom << endl; //可以直接访问;
cout << b->m_bedroom << endl; //不能直接访问,除非写了第二行;
}
int main(){
goodfriend g1;
g1.visit();
return 0;
}
class building{
friend void goodfriend::visit(); //第二行
public:
building();
string m_sittingroom;
private:
string m_bedroom;
};
class goodfriend(){
public:
void visit();
void visit2();
};
int main(){
return 0;
}
成员函数重载:
class person{
public:
person operator+(person &p){
person temp;
temp.m_a = this->m_a + p.m_a;
temp.m_b = this->m_b + p.m_b;
return temp;
}
int m_a;
int m_b;
};
全局函数重载:
class person{
public:
person operator+(person &p1, person &p2){
person temp;
temp.m_a = p1.m_a + p2.m_a;
temp.m_b = p1.m_b + p2.m_b;
return temp;
}
//函数重载:
person operator+(person &p1, int num){
person temp;
temp.m_a = p1.m_a + num;
temp.m_b = p1.m_b + num;
return temp;
}
int m_a;
int m_b;
};
运算符重载也可以发生函数重载。
作用:可以输出自定义数据类型。
class person{
friend ostream& operator<<(ostream &cout, person &p);
public:
//不用成员函数来实现左移运算符重载;
//只用全局函数来重载:
ostream& operator<<(ostream &cout, person &p){
cout << m_a << " " << m_b << endl;
return cout;
}
int m_a;
int m_b;
};
int main(){
person p1;
p1.m_a = 10;
p1.m_b = 20;
//cout << p1; //返回void时,不能在后面追加 <
cout << p1 << endl;
return 0;
}
前置递增返回引用,后置递增返回值:
class myinteger{
friend ostream& operator<<(ostream& cout, myinteger myint);
public:
myinteger(){
m_num = 0;
}
//重载前置++运算符,返回引用是为了一直对一个数据进行操作
myinteger& operator++(){
m_num++;
return *this;
}
//重置后置++运算符,不能返回引用
myinteger operator++(int){ //int代表占位参数,可以用于区分前置和后置递增
myinteger temp = *this;
m_num++;
return temp;
}
private:
int m_num;
};
ostream& operator<<(ostream& cout, myinteger myint){
cout << myint;
return cout;
}
int main(){
myinteger myint;
cout << ++(++myint) << endl; //加引用后返回2,不加则返回1
cout << (myint++) << endl;
return 0;
}
class person{
public:
person(int age){
m_age = new int(age);
}
~person(){
if(m_age!=NULL){
delete(m_age);
m_age = NULL;
}
}
person& operator=(person &p){
//编译器提供的是浅拷贝:
//m_age = p.m_age;
if(m_age!=NULL){
delete(m_age);
m_age = NULL;
}
//深拷贝:
m_age = new int(*p.m_age);
//返回对象本身:
return *this;
}
int *m_age;
};
void test(){
person p1(18);
person p2(20);
person p3(30);
p3 = p2 = p1;
cout << *p1.m_age << endl;
cout << *p2.m_age << endl;
cout << *p3.m_age << endl;
}
int main(){
test();
return 0;
}
class person{
public:
person(string name, int age){
m_name = name;
m_age = age;
}
bool operator==(person &p){
if(m_name==p.m_name && m_age==p.m_age){
return true;
}
return false;
}
string m_name;
int m_age;
};
void test(){
person p1("Tom", 18);
person p2("Tom", 18);
if(p1==p2){
cout << 1 << endl;
}
}
int main(){
test();
return 0;
}
函数调用运算符()也可以重载;
由于重载后使用的方式非常像函数的调用,因此称为仿函数;
仿函数没有固定写法,非常灵活。
class myprint{
public:
void operator()(string test){
cout << test << endl;
}
};
void func(string test){
cout << test << endl;
}
void test(){
myprint p1;
p1("Hello world");
func("Hello world");
}
int main(){
test();
return 0;
}