面向对象基础
3.封装(重点)
把属性和行为作为一个整体表现生活中的事物
对属性和行为的加以权限限制
留有public接口方便访问
通常属性设为private加以权限,自己控制它的读写
#include <iostream>
using namespace std;
class Person{
private:
string name; //可读可写
string address; //只读
string password="123456"; //只写
public:
void set_name(string n){
name=n;
}
void get_name(){
cout<<name;
}
void get_address(){
cout<<"华清远见"<<endl;
}
void set_password(string p){
password=p;
}
void show(){
cout<<name<<" "<<password<<endl;
}
};
int main()
{
Person p;
//string s="hello";
//p.name=s;错误 私有成员不能直接访问
p.set_name("张三");
p.show();
p.get_address();
}
4.构造函数(重点)
构造函数是一个特殊的函数 :
名字和类名相同
没有返回值
如果不写系统会有默认的构造,如果给出就没有默认的构造函数。默认的构造函数函数体中没有任何内容,一般我都会重构一个构造函数来实现我想要的功能,默认的留着。
#include <iostream>
using namespace std;
class Person{
private:
string name;
string address;
string password="123456";
public:
// Person(){ //直接给出默认值 不灵活
// name="张三";
// address="华清远见";
// password="88888";
// }
Person(string n,string a,string p){
name=n;
address=a;
password=p;
}
void set_name(string n){
name=n;
}
void get_name(){
cout<<name;
}
void get_address(){
cout<<address<<endl;
}
void set_password(string p){
password=p;
}
void show(){
cout<<name<<" "<<password<<endl;
}
};
int main()
{
Person p("李四","济南","1234");
p.get_address();
p.get_name();
}
4.1构造函数默认值
#include <iostream>
using namespace std;
class Person{
private:
string name;
string address;
string password="123456";
public:
// Person(){
// name="张三";
// address="华清远见";
// password="88888";
// }
Person(string n,string a="山东",string p="0000"){
name=n;
address=a;
password=p;
}
void set_name(string n){
name=n;
}
void get_name(){
cout<<name<<endl;
}
void get_address(){
cout<<address<<endl;
}
void set_password(string p){
password=p;
}
void show(){
cout<<name<<" "<<password<<" "<<address<<endl;
}
};
int main()
{
Person p("王五");
p.get_address();
p.get_name();
p.show();
Person p2("小明","青岛","88888888");
p2.show();
Person * p3=new Person("小红","上海","7777");
p3->show();
delete p3; //堆内存对象 需要delete
p3=NULL;
}
4.2构造重载
#include <iostream>
using namespace std;
class Person{
private:
string name;
string address;
string password="123456";
public:
Person(){
name="张三";
address="华清远见";
password="88888";
}
Person(string n,string a="山东",string p="0000"){
name=n;
address=a;
password=p;
}
void set_name(string n){
name=n;
}
void get_name(){
cout<<name<<endl;
}
void get_address(){
cout<<address<<endl;
}
void set_password(string p){
password=p;
}
void show(){
cout<<name<<" "<<password<<" "<<address<<endl;
}
};
int main()
{
Person p; //调用无参构造函数
p.show();
}
4.3初始化列表
对属性进行初始化赋值
#include <iostream>
using namespace std;
class Person{
private:
string name;
string address;
string password="123456";
public:
Person(){
name="张三";
address="华清远见";
password="88888";
}
Person(string n,string a,string p): name(n),address(a),password(p){}
void set_name(string n){
name=n;
}
void get_name(){
cout<<name<<endl;
}
void get_address(){
cout<<address<<endl;
}
void set_password(string p){
password=p;
}
void show(){
cout<<name<<" "<<password<<" "<<address<<endl;
}
};
int main()
{
Person p;
p.show();
Person p2("李四","济南","12345");
p2.show();
}
5.析构函数 (掌握)
对象销毁时会自动调用,没有参数和返回值 也就不能重载
栈内存对象 编译器自动销毁 自动调用析构
堆内存对象 delete之后 自动调用析构函数
析构函数在对象销毁 做善后工作,回收new方式创建的资源,比如你的类属性中有指针类型那么当你深拷贝后,就要释放这个空间。
#include <iostream>
using namespace std;
class Cat{
private:
string name;
public:
Cat(string n):name(n){
cout<<name<<"的构造函数调用"<<endl;
}
~Cat(){
cout<<name<<"的析构函数"<<endl;
}
};
int main()
{
Cat c("小花");
Cat * c2=new Cat("小白"); //堆内存对象需要 手动delete
delete c2;
}
6.作用域限定符(熟悉)::
std是c++中的标准命名空间,里面包含了很多内容。
using namespace std;
#include <iostream>
using namespace std;
int a=10;
namespace my_space {
int a=30;
}
using namespace my_space; //使用创建的命名空间
int main()
{
int a=20;
cout<<a<<endl;
cout<<"全局变量里的:"<<::a<<endl;
cout<<"my_space里的"<<my_space::a<<endl;
cout<<"hello"; //如果没有使用std命名空间 应是std::cout<<"hello";
}
作用域限定符应用
类的成员在类内做声明,类外定义时,类外定义需要加上作用域限定符
#include <iostream>
using namespace std;
class Student{
private:
string name;
public:
Student(string n){
name=n;
}
void show(); //类内声明
};
void Student::show(){ //类外定义
cout<<name;
}
int main()
{
Student s("小明");
s.show();
}
7.explicit(熟悉)
屏蔽隐式调用构造函数,防止误操作。
#include <iostream>
using namespace std;
class Student{
private:
string name;
public:
explicit Student(string n);
void show(); //类内声明
};
void Student::show(){ //类外定义
cout<<name;
}
Student::Student(string n):name(n){}
int main()
{
Student s("小明");
s.show();
string str="小强";
// Student s2=str; //隐式调用构造函数 加explicit后不允许
// s2.show();
}
8.拷贝构造函数(掌握)
不手写编译器会默认添加一个拷贝构造函数
#include <iostream>
#include <string.h>
using namespace std;
class Phone{
private:
string brand;
string model;
public:
Phone(string b,string m);
void show();
};
Phone::Phone(string b,string m){
brand=b;
model=m;
}
void Phone::show(){
cout<<brand<<" "<<model<<endl;
}
int main()
{
Phone p("苹果","14");
p.show();
Phone p2(p);
p2.show();
}
手写拷贝
对象之间相互独立 对象之间的属性也是独立的。只是把一个对象的值赋给了另一个对象
浅拷贝
#include <iostream>
#include <string.h>
using namespace std;
class Phone{
private:
string brand;
string model;
public:
Phone(string b,string m);
void show();
Phone(const Phone & p){ //不写默认会有
cout<<"拷贝构造函数"<<endl;
brand=p.brand;
model=p.model;
}
};
Phone::Phone(string b,string m){
brand=b;
model=m;
}
void Phone::show(){
cout<<brand<<" "<<model<<endl;
cout<<&brand<<" "<<&model<<endl;
}
int main()
{
Phone p("苹果","14");
p.show();
cout<<"------------"<<endl;
Phone p2(p);
p2.show();
}
值之间的传递。当属性有指针时出现问题
两个对象的成员变量保存同一个地址,指向同一片地址。
两个对象的
#include <iostream>
#include <string.h>
using namespace std;
class Dog{
private:
char * name;
public:
Dog(char * n){
name=n;
}
void show(){
cout<<name<<endl;
}
Dog(const Dog & d){
name=d.name;
}
};
int main()
{
char a[10]="xiaobai";
Dog d1(a); //d1.name指向a
Dog d2(d1); //d1.name也指向a
d1.show(); //xiaobai
d2.show(); //xiaobai
strcpy(a,"doudou");
d1.show(); //doudou
d2.show(); //doudou
}
如果是属性中有指针类型,地址也会拷贝过去。破坏对象之间的独立性,就需要每个对象创建一个属于自己的空间
深拷贝
#include <iostream>
#include <string.h>
using namespace std;
class Dog{
private:
char * name;
public:
Dog(char * n){
name=new char[20];
strcpy(name,n);
}
void show(){
cout<<name<<endl;
}
Dog(const Dog & d){
name=new char[20];
strcpy(name,d.name);
}
};
int main()
{
char a[10]="xiaobai";
Dog d1(a);
Dog d2(d1);
d1.show(); //xiaobai
d2.show(); // //xiaobai
strcpy(a,"doudou");
d1.show(); //xiaobai
d2.show(); xiaobai
}
//堆
Phone * p3 = new Phone("苹果","14");
p3->show();
Phone * p4 = new Phone(*p3);
p4->show();
9.this指针(重点)
this指针指向当前对象的首地址
#include <iostream>
#include <string.h>
using namespace std;
class Test{
private:
string str1;
string str2;
public:
Test(string str1,string str2){
this->str1=str1;
this->str2=str2;
}
void show(){
cout<<this<<endl;
}
void method(){
cout<<str1<<" "<<str2<<endl;
}
};
int main()
{
Test t2("1","2");
cout<<&t2<<endl;
t2.show();
t.method();
}
9.1this指针应用1
this指针应用1:当参数和属性重名时 用this指针进行区分
#include <iostream>
#include <string.h>
using namespace std;
class Test{
private:
string str1;
string str2;
public:
Test(string str1,string str2){
this->str1=str1;
this->str2=str2;
}
void show(){
cout<<str1<<" "<<str2;
}
void show2(){
this->show();
}
void method(){
cout<<str1<<" "<<str2<<endl;
}
};
int main()
{
// Test t;
// cout<<&t<<endl;
// t.show();
Test t2("1","2");
t2.show2();
}
9.2this指针应用2 链式调用
函数返回值时 类的引用的时候,需要返回*this
#include <iostream>
#include <string.h>
using namespace std;
class Value{
private:
int value=1;
public:
Value & add(int i){
value+=i;
cout<<this<<endl; //地址都是一样的
return *this; //*this是当前对象
}
void get_value(){
cout<<value;
}
};
int main()
{
Value v;
v.add(1).add(2).add(3).add(4);
v.get_value();
}
10.static
static修饰局部变量 static只创建一次
#include <iostream>
#include <string.h>
using namespace std;
class Test{
public:
void test(){
int a=1;
static int b=1;
a++;
b++;
cout<<a<<" "<<b<<endl;
}
};
int main()
{
Test t;
t.test(); //2 2
t.test(); //2 3
t.test(); //2 4
}
static修饰成员变量以下特点:
此类中所有的对象都共享此变量
非const 的静态成员变量 必须类里面声明 在类外初始化式
程序运行的时候创建,程序结束的时候销毁
#include <iostream>
#include <string.h>
using namespace std;
class Test{
public:
static int a;
};
int Test::a=1;
int main()
{
Test t1;
cout<<t1.a<<" "<<&t1.a<<endl;
t1.a++;
Test t2;
cout<<t2.a<<" "<<&t2.a<<endl;
}
静态函数
static修饰的函数
静态函数的特点;
静态成员函数不能访问类中的非静态变量。因为没有this指针,不具体作用于某个对象
静态成员函数不能访问类中的非静态函数
如果静态成员函数声明与定义分离的时候,只需要在声明出使用static关键字
#include <iostream>
#include <string.h>
using namespace std;
class Test{
public:
static int a;
int b=2;
static void show(){
//静态成员函数不能访问类中的非静态变量。
// cout<<b<<endl;//相当于cout<<this->b<<endl;
}
};
int Test::a=1;
int main()
{
cout<<Test::a<<endl; //此时没有对象 也就没有this指针
//cout<<Test::show();
}
静态函数访问非静态函数。
#include <iostream>
#include <string.h>
using namespace std;
class Test{
public:
static int a;
int b=2;
void change(){
b++;
}
static void show(){
//change(); //b++ 不可以,也会操作成员变量
}
};
int Test::a=1;
int main()
{
cout<<Test::a<<endl;
//cout<<Test::show();
}
错误例子演示
#include <iostream>
#include <string.h>
using namespace std;
class Test{
private:
int b;
public:
static int a;
void change(){
b++;
}
Test(int bb){
b=bb;
}
void show(){
cout<<b<<endl;
}
static void show2(){
cout<<b<<endl;
}
};
int Test::a=1;
int main()
{
Test t1(2);
t1.show(); //t1.b=2
Test t2(3); //t2.b =3
t2.show();
Test::show2();
}
10.const关键字
const表示常量的意思,意味着在运行的时候其修饰的内容不可以改,编译的时候可以更改
常成员函数
常成员函数就是在函数上加const关键字,其特点:
1.可以访问非const成员属性,但是不能更改其值
2.常成员函数也不能访问非const成员函数。
#include <iostream>
using namespace std;
class Test{
private:
int a=1;
public:
void get_a() const{
//a++;错误
cout<<a<<endl;
}
void set_a(){
a++;
}
void method() const
{
cout<<a<<endl;
//a++; 不能修改
//set_a(); 错误
}
};
int main()
{
Test t;
t.method();
}
当成员函数只读时 后面需加上const修饰
常量对象
const修饰的对象。特点:
1.常对象可以访问属性,但是不能修改其值
2.常对象不能调用任何非const的成员函数
#include <iostream>
using namespace std;
class Test{
private:
int a=1;
public:
void get_a() const{
cout<<a<<endl;
}
void set_a(){
a++;
}
void method() const
{
cout<<a<<endl;
}
};
int main()
{
Test const t;
t.get_a();
//t.set_a(); 错误
const Test t2;//const也可以放在Test前
}
常成员变量
const修饰的成员变量。就是常成员变量:
1.运行时常成员变量的值不可改
2.对它进行初始化 ,要么是定义的时候直接初始化。或者是构造函数初始化列表赋值
#include <iostream>
using namespace std;
class Test{
private:
int a=1;
const int b;
const int c=4;//1.直接赋值
public:
// Test(int a, int b){ //不能对b赋值
// this->a=a;
// this->b=b;
// }
//2.需要构造初始化列表来赋值
Test(int a,int b):a(a),b(b=2){}
void get_a() const{
cout<<a<<endl;
cout<<b<<endl;
cout<<c<<endl;
}
void set_a(){
a++;
}
};
int main()
{
Test t(2,3);
t.get_a();
}
const修饰局部变量
给局部变量如参数加const修饰。函数参数值是不可以更改的
#include <iostream>
using namespace std;
class Test{
public:
void func(const int b){
//b++; 错误
cout<<b<<endl;
const int c=10;
//c++; 错误
cout<<c<<endl;
}
};
int main()
{
Test t1;
t1.func(2);
}