文章目录
一.命名空间,关键字升级,C++对C的加强(引用),C++对C的函数扩展
(一)命名空间
1、定义:namespace 名字{变量、函数}
使用方法
(1)使用作用域限定符:命名空间的名字::变量名或者函数名
(2)使用using关键字导入明明空间:using 命名空间(可能多个命名空间含有相同变量名产生二义性) 或者 using 命名空间::变量名或者函数名
::作用域限定符
2、using namespace std:标准库命名空间
作用:C++为了防止和C冲突,将新的一些函数定义在标准库中。
使用注意事项
(1)源文件不能访问其他源文件的命名空间
(2)当多个源文件的命名空间名字相同时:
如果两个命名空间函数名或者变量名没有出现重复,就会合并,可理解为追加
如果两个命名空间有相同的函数名或者变量名,就会报错
#include <iostream>
//filename:add.cpp
//static int count = 5; //c语言解决命名冲突的方法
namespace A
{
int count =5;
void print()
{
std::cout << "hello world" <<std:: endl ;
}
}
namespace C
{
int count = 6;
}
//using namespace A
//using A::print
int add(int a,int b)
{
return a-b-A::count;
}
#include <iostream>
extern int add(int a,int b);
//using namespace std //标准库命名空间
int main()
{
std::cout<<add(0,0)<<std::endl;
return 0;
}
(二)输入输出
1、对象:
(1)cin:输入流
(2)cout:输出流
(3)cerr:错误流
(4)clog:日志流 有缓冲
2、流运算符:
(1)>>:输入
(2)<<:输出
3、注意事项:
(1)printf:有行缓冲(满一行或者遇到"\n"输出)
使用printf调试时,一定要加"\n"或者手动刷新缓冲区
(2)scanf:输入前,刷新缓冲区
(3)cout:也有行缓冲,加上endl
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
using namespace std;
int main()
{
/*
int fd = open("a.txt",O_RDWR | O_CREAT,0655);
if(fd==-1)
{
cerr<<"error"<<endl;
}
cerr<<"hello" ;
while(1);
printf("hello");
while(1);
*/
int num;
char ch;
char src[100];
cin>>num;
//解决行冲突
//getchar();//c语言接收换行符
cin.get(); //c++接收换行符
cin>>ch;
cin.get();
//cin>>src;
cin.getline(src,100); //接收一行100个字符的内容
cout<<"num="<<num<<endl;
cout<<"ch="<<ch<<endl;
cout<<"src="<<src<<endl;
return 0;
}
(三)C++对C的实用性加强
1、基本语句的升级
(1)for语句:优化了循环变量的作用域
(2)条件表达式:可以做左值
2、关键字的升级
(1)register关键字的升级:若对一个register变量取地址,会将该变量重新保存到内存中。
C语言中:尽可能的将该变量保存到cpu内部寄存器中,从而省去从内存中抓取数据的时间,提高程序运行的效率;
C语言中register使用注意事项:
只能修饰局部,不能修饰全局变量和函数
C语言中register修饰变量,不能通过&获取该变量的地址
register修饰的变量类型,必须是时cpu所能够接受的类型
(2)const关键字的升级:const修饰的变量是常量
C语言中const修饰的变量是只读变量
地址之间的赋值必须是const对const
(3)auto关键字:类型推导,实现高效编程
example:
string::interator it = s1.begin();
aoto inter2 = s1.begin();
这样两个类型就一致了
C语言中auto关键字:自动变量,只是用来说明该变量的作用域;相当于局部变量
(4)using关键字的升级:替代C语言中的typedef的关键字
typedef关键字的作用:给类型重命名;提高代码的可读性、移植性;
3、类型的升级
(1)引入了bool类型 占一个字节
(2)引入了”引用“
1、定义:给变量起别名,定义引用必须初始化,一旦绑定就不能再次绑定到其他变量上。
2、作用:解决了函数传值和传地址的问题。
3、应用场景:作为函数的形参,作为函数的返回值(函数调用可以用作左值)
4、常引用:const修饰的引用,绑定常量
5、引用的分类
左值引用(&):只能绑定在左值;右值引用(&&):只能绑定在右值
左值:可以取地址,可以修改
右值:不可以取地址,不可以修改
右值引用的目的:实现对象移动,解决临时对象拷贝开销问题;
std::move():将左值转化成右值
6、引用是不是数据类型?占不占用内存空间?
引用不是数据类型,运行时不占用内存空间,编译时预留内存空间!!!!
引用不是一种独立的数据类型,对引用只有声明没有定义
7、指针和引用的区别?
指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元,即指针是一个实体;而引用跟原来的变量实质上是一个东西,只不过是原变量的一个别名而已。
8、什么是对象移动?作用是什么?
对象移动:本身并不移动对象,只是将对象的类型转换为右值。
对象移动的作用:实现移动构造函数和移动赋值运算符
C语言中传地址,才可以改变两个实参的值。
(3)用new、delete运算符来替代malloc、free
1、malloc 按照字节为单位,new按照数据类型的个人为单位
2、malloc不能初始化内存,new可以初始化
3、malloc是函数,new是运算符
(四)C++对C的升级
1、函数的升级
(1)引入inline关键字修饰函数:用(内存)空间换运行时间(减少函数的调用和返回)
限制:
内联函数不可含有循环
内联函数不可含有静态变量
内联函数不可为递归函数
内联函数不可含有错误处理
注意事项:
一般内联函数必须在第一次调用之前
(2)引用了默认参数:可以给形参设定默认参数(规则:默认参数右边的参数必须全为默认参数)
(3)可以使用函数的重载:可以使用相同函数名,重载规则:形参的个数、类型或者顺序不同。
初始int add(int a,int b)
重载1:int add(int a,int b,int c)
重载2:int add(char a,char b)
重载3:int add(int b,int a)
注意事项:
函数返回值不能作为重载条件;默认参数值会影响重载。
(4)引入了参数占位符
int add(int a,string b,int)
最后一个int为参数占位符,提示以后可能会升级.
#include <iostream>
#include <string>
using namespace std;
int add(int a, int b)
{
return a + b;
}
int sup(int a,int b=1)//默认参数
{
return a-b;
}
//函数的重载
int add(int a,int b,int c)
{}
int add(double a,char b)
{}
void swap(int &left, int &right)
{
int temp;
temp = left;
left = right;
right = temp;
}
int & test()
{
static int num = 5;
cout << num << endl;
return num;
}
int func(const int &num1, const int &num2)
{
}
int main()
{
#if 0
//C++对C的升级:基本语句的升级
//for语句:优化循环变量的作用域
for (int i = 0; i < 100; i++)
{
}
//条件表达式:可以做左值
int a = 5;
int b = 6;
int max = a > b ? a : b;
(a > b ? a : b) = 69; //只修改b的值
cout << b << endl;
//C++对C的升级:关键字的升级
//register关键字的升级:若对register变量取地址,会将该变量重新保存到内存中;
//C语言: //2\register修饰变量,不能通过&获取该变量的地址;
register int count = 6;
int *p = &count;
//const关键字的升级:const修饰是常量;
//地址之间的赋值必须是const对const;
const int num = 5;
const int *p_num = #
//*p_num = 7;
//auto关键字
//C语言auto关键字:自动变量,只是用来说明该变量的作用域;相当于局部变量
//C++11:auto:类型推导,实现高效编程
auto ch1 = 'a';
auto str = "hello world";
auto d = 1.12345;
string s1 = "hello";
string::iterator it = s1.begin();
auto it2 = s1.begin();
//using关键字的升级:替代C语言typedef的关键字
//typedef关键字的作用:给类型重命名的;提高代码可读性、移植性的;
using Int = int;//typedef int Int;
using Len = int;//typedef int Len;
using P_FUNC = int (*)(int,int);//typedef int (*P_FUNC)(int,int);
Int c; //int c;
Len c2;
add(6,5);
P_FUNC p_func = add;//int (*p_func)(int,int) = add;
p_func(6,5);
//C++对C的升级:类型的升级
//引入了bool类型
bool flag = false;
#endif
#if 0
//引入了“引用”
//引用:给变量起别名,定义引用必须初始化,一旦绑定就不能再次绑定到其他变量上;
//作用:解决函数传值和传地址问题;
//应用场景:作为函数的形参; 作为函数的返回值(函数的调用可以做左值)
//常引用:const修饰的引用; 绑定常量
int temp = test();
test() = 10;
test();
int left = 5;
int right = 6;
int &l_left = left;
cout << left << endl;
swap(left,right);
cout << left << " " << right;
int count = 5;
const int &l_count = 5;
func(5,6);
#endif
//C++11引用的分类:左值引用(&):只能绑定左值、右值引用(&&):只能绑定在右值
//左值:可以取地址可以修改 右值:不能取地址,不能修改
//std::move()将左值转换为右值
//为什么引用右值引用? 实现对象移动,解决临时对象拷贝开销的问题;
int num = 5;
int &l_num = num;//左值引用
int &&r_num = 5;//右值引用
int &&r_num2 = std::move(num);//
//作用:
//引用是不是数据类型?(不是)它占不占用内存空间?(运行时不占用内存空间,编译时预留内存空间)!!!
//指针和引用的区别?
//什么是对象移动?对象移动的作用?·
//C++ maloc\free
//new delete
char *ptr = new char[100];
char *ptr1 = new char('a');
int *p = new int (5);
delete []ptr;
delete ptr1;
ptr = nullptr;
ptr1 = nullptr;
//malloc free vs new delete
add(6,5);
add(6,5);
return 0;
}
二.结构体升级,string类,vector,强制类型转换
2、结构体的升级
(1)定义方式不同:
C中定义:strcut Student stu;
C++中定义:Student stu;
(2)结构体中可以保存函数
(3)可以设置权限
public:可以在结构体内外访问
private/protected:只能在结构体内访问
(4)可以继承
(注)class VS struct
区别
默认访问权限:class 默认private struct默认public
命名:class(类) struct(结构体) class定义称之为对象 struct定义称之为变量
类内实现的方法,编译器会优化为inline函数,所以成员方法最好类外实现
为什么引用类?
具有封装性(保证代码功能的独立:设置访问权限)->提高代码维护性
#include <iostream>
#include <string.h>
using namespace std;
//class vs struct
//different:
//read permission:class 默认 private struct默认public
//name: class struct class 对象 struct 结构体
//引入类:封装性(保证代码独立,设置访问权限)--提高维护性
struct Person //class Person
{
void printhello()
{
cout<<"hello"<<endl;
}
};
class Student //struct
{
//update3:setting read permission: public\private\protected
//类内实现的方法,编译器会优化为inline函数
//成员方法类外实现
public:
int num;
char name[20];
int age; //成员变量
public:
//update2:save func
void print(){ //成员方法
cout<<"num="<<num<<endl;
}
};
int main()
{
//update1 :define type
Student stu;
stu.num = 1;
stu.age = 20;
strcpy(stu.name,"zhangsan");
stu.print;
return 0;
}
student.cpp
#include "student.h"
int main()
{
Student::print;
return 0;
}
student.h
#pragma once
#include <iostream>
using namespace std;
class Student //struct
{
public:
int num;
char name[20];
int age; //成员变量
public:
void print(){ //成员方法
cout<<"num="<<num<<endl;
}
};
(五)string类
1、定义并初始化
string s1 = “hello world”;
2、属性
cout << s1.size() << endl;返回有多少个字符
cout << s1.length() << endl;长度=size
3、遍历
(1)支持数组的访问方式
(2)通过函数访问
区别:
[ ]不会检查后是否越界
at检查:如果越界,产生异常->更加安全
for函数:
foeach函数:
迭代器(类似于指针):
获取指向第一个字符的迭代器
获取指向最后一个字符的迭代器
正向迭代器:
反向迭代器:
4、插入
string &insert(int p0, const char *s);
string &insert(int p0, const char *s, int n);
string &insert(int p0,const string &s);
string &insert(int p0,const string &s, int pos, int n);
//前4个函数在p0位置插入字符串s中pos开始的前n个字符
string &insert(int p0, int n, char c);//此函数在p0处插入n个字符c
iterator insert(iterator it, char c);//在it处插入字符c,返回插入后迭代器的位置
void insert(iterator it, const_iterator first, const_iterator last);//在it处插入[first,last)之间的字符
void insert(iterator it, int n, char c);//在it处插入n个字符c
5、删除
iterator erase(iterator first, iterator last);//删除[first,last)之间的所有字符,返回删除后迭代器的位置
iterator erase(iterator it);//删除it指向的字符,返回删除后迭代器的位置
string &erase(int pos = 0, int n = npos);//删除pos开始的n个字符,返回修改后的字符串
6、替换
string &replace(int p0, int n0,const char *s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const char *s, int n);//删除p0开始的n0个字符,然后在p0处插入字符串s的前n个字符
string &replace(int p0, int n0,const string &s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const string &s, int pos, int n);//删除p0开始的n0个字符,然后在p0处插入串s中从pos开始的n个字符
string &replace(int p0, int n0,int n, char c);//删除p0开始的n0个字符,然后在p0处插入n个字符c
string &replace(iterator first0, iterator last0,const char *s);//把[first0,last0)之间的部分替换为字符串s
string &replace(iterator first0, iterator last0,const char *s, int n);//把[first0,last0)之间的部分替换为s的前n个字符
string &replace(iterator first0, iterator last0,const string &s);//把[first0,last0)之间的部分替换为串s
string &replace(iterator first0, iterator last0,int n, char c);//把[first0,last0)之间的部分替换为n个字符c
string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last);//把[first0,last0)之间的部分替换成[first,last)之间的字符串
7、查找
8、比较
#include <iostream>
#include <string.h>
using namespace std;
int main ()
{
const char *ptr = "hello world";
char src[20]="hello world";
//1 定义并初始化
string s1= "hello world";
string s2('a',100);
string s3("hello world");
string s4="";
#if 0
//2属性
if(s4.empty()==true)
{
cout <<"s4 is empty"<<endl;
}
cout<<s1.size()<<endl;//返回多少个字符
cout<<s1.length()<<endl;//length=size
//3遍历
cout <<s1[0]<<endl; //支持数组的访问方式
cout<<s1.at(0)<<endl; //at hanshu
//区别:[]不会检查是否越界 at检查:如果越界,产生异常
//cout<<s1[100]<<endl;
//cout<<s1.at(100)<<endl;//safe
for(int i=0;i<s1.size();i++)
{
cout<<s1[i];//s1.at(i)
}
putchar('\n');
for(auto temp:s1)
{
cout<<temp;
}
putchar('\n');
//迭代器:指针类型
//迭代器类型:string::iterator
//string::iterator it;
//it = s1.begin();//获取指向di一个字符的迭代器
//it = s1.end(); //获取指向最后一个字符的下一个空间的迭代器('\0')
//正向迭代器反向
for(auto it = s1.begin();it !=s1.end();it++)
{
cout<<*it;
}
putchar('\n');
//反向迭代器
for(auto it = s1.rbegin();it !=s1.rend();it++)
{
cout<<*it;
}
putchar('\n');
#endif
//insert
//s1.insert(2,"jsetc");
//cout<<s1<<endl; //hejsetcllo world
string temp="jsetc";
string::iterator it;
for(it=s1.begin();it!=s1.end();it++)
{
if(*it=='e')
{
break;
}
}
s1.insert(++it,temp.begin(),temp.end());
//delete
for(it=s1.begin();it!=s1.end();it++)
{
if(*it=='l')
{
//break;
s1.erase(it);
}
else
{
it++;
}
}
//s1.erase(it);
//replace
//s3.swap(s4);
s3.replace(s3.begin(),s3.end(),s4.begin(),s4.end());
cout<<"s3="<<s3<<endl;
cout<<"s4="<<s4<<endl;
//find
string::size_type t;
if( (t=s1.find('z') ) == string::npos )
{
cout <<"not find z\n";
}
cout<<"t = "<<t<<endl;
//compare
return 0;
}
vector
//vi插入10个整数,删除里面的奇数,然后输出结果
#include <iostream>
#include <vector>
#include <string.h>
#include <stdio.h>
using namespace std;
int main()
{
vector<int> vi ;
int a ;
for(int i=0;i<5;i++)
{
scanf("%d",&a);
vi.push_back(a);
}
//vector<int>::iterator it;
for(auto it=vi.begin();it !=vi.end();)
{
if((*it)% 2 != 0)
{
vi.erase(it);
}
else{
it++;
}
}
for(auto it=vi.begin();it !=vi.end();it++)
{
cout<<*it<<" ";
}
putchar('\n');
return 0;
}
//vs插入5个字符串,删除字符串中后缀为奇数的字符串,然后输出结果
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
int main()
{
vector<string> vs;
string str;
for(int i=0;i<5;i++)
{
cin>>str;
/*
auto it=str.end()-1;
if( (*it)%2 == 0 )
*/
vs.push_back(str);
}
/*
for(auto it=vs.begin();it!=vs.end();it++)
cout<<*it<<" ";
putchar('\n');
*/
for(auto it=vs.begin();it!=vs.end();it++)
{
auto itt=(*it).end()-1;
if( (*itt)%2 == 0 )
cout<<*it<<" ";
}
putchar('\n');
return 0;
}
//把I am from shanghai逆序为shanghai from am I
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
int main()
{
vector<string> vs;
string str;
for( int i =0; i<4 ; i++ )
{
cin>>str;
vs.push_back(str);
}
for(auto it=vs.rbegin() ; it!=vs.rend() ; it++)
{
cout<<*it<<" ";
}
putchar('\n');
return 0;
}
(六)C++独有的类型的转换
隐式转换和显式转换
(1)static_cast:相关类型转换(隐式类型转换),父类和子类,void *和其他类型指针的转换。
优点:做类型检查(检查类型是否可以转换)
(2)reinterpret_cast:相当于C语言的强制类转换,可以将任意指针类型进行转换。
(3)const_cast:将指针或者引用的const属性去除。
#include <iostream>
using namespace std;
int main()
{
//c++类型转化
//static_cast:相关类型转换,父类和子类,void* 和其他类型指针转换
int num = 5;
double b = static_cast<double>(num);
char ch = static_cast<char>(num);
int *p_num = #
void *p = p_num;
int *p_num2 = static_cast<int*>(p); //(int *)p;
//优点:检查类型是否keyi转换
//char *ptr = static_cast<char *>(p_num); //error
//reinterpret_cast相当于c语言的强制类型转换,可以将任意类型指针进行转换
char *ptr = reinterpret_cast<char *>(p_num2);
//const_cast把指针或引用的const去除
const int n=5;
const int *p_n = &n;
int *temp = const_cast<int *>(p_n);
//dynamic_cast多态
return 0;
}
三.构造函数,友元函数,初始化表,静态成员变量
构造函数:
1.函数名和类名相同
2.无返回值
特点:1.构造函数允许重载
2.每一个类都有自带的默认构造函数
3.一旦自己定义了构造函数,会将原本的默认构造函数覆盖
4.类的对象作为参数传入,会调用复制构造函数,会创建新的对象
this指针
构造函数的返回值:构造函数返回对象本身
类complex的复制构造函数不能带有complex类型的参数
当类没有复制构造函数的时候,=的作用就只是引用
匿名对象:生命周期只存在于创建的那一行
析构函数
friend关键字:友元函数,调用类的成员方法
函数:malloc 在堆上进行申请空间不会调用构造函数和析构函数
关键字:new delete 创建时会自动调用构造函数和析构函数
初始化表:const修饰的成员变量只能在初始化表进行初始化
void show( const complex & s1 )形参s1不可被修改
const int show (complex & s1)返回值不可被修改
int show (complex & s1)const 常成员函数,该函数内不可修改任何成员变量
static修饰成员变量:
1.静态成员不占用对象空间
2.静态成员属于整个类,整个类(所有对象)共享这个静态变量
3.静态成员变量定义必须初始化,必须在类外初始化
4.静态成员函数:操作静态成员变量,不能操作其他变量
完善虚数类
#include <iostream>
#include <stdio.h>
using namespace std;
class complex
{
public:
complex( int real,int vur );
complex();
friend void show(const complex &s1); //友元函数
void show2(complex &s1)const;
complex ( const complex &s1 ); //类complex的复制构造函数不能带有complex类型的参数
complex & add( complex &s1 );
~complex();//析构函数
static void showstatic();
private:
int real;
int vur;
static int count;
};
int complex::count = 0; //静态成员变量定义必须初始化,必须在类外初始化
void complex::showstatic()
{
cout<<count<<endl;
}
void complex::show2(complex &s1)const
{
//this->real ++; //error
}
complex::complex( int real,int vur )
{
cout<<"number constructor"<<endl;
this->real = real;
this->vur = vur;
}
complex::complex()
{
cout<<"no number constructor "<<endl;
count++;
}
void show( const complex & s1 )
{
cout<<s1.real<<"+"<<s1.vur<<"i"<<endl;
}
complex::complex ( const complex &s1 ): real(real) ,vur(vur) //const int vur
{ //类complex的复制构造函数不能带有complex类型的参数
cout<<"copy constructor"<<endl;
//this->real = s1.real;
//this->vur = s1.vur;
}
complex & complex::add( complex &s1 )
{
static complex s2 ;
s2.real=this->real + s1.real ;
s2.vur=this->vur + s1.vur;
return s2;
}
complex::~complex()//析构函数
{
cout<<"disconstructor complete"<<endl;
}
int main()
{
/*
complex s1(1,2);//有参构造函数
//s1.show();
complex s2;//无参构造函数
complex s3(s1);//复制构造函数
s3.show();
complex s4 =s1;//当类没有复制构造函数的时候,=的作用就只是引用
s4.show();
*/
/*
complex s1(1,2);
complex s2(2,3);
complex s3;
s3=s2.add(s1);
s3.show();
*/
//complex(3,4); //匿名对象,生命周期只存在于创建的那一行
/*
complex *t1 = (complex * )malloc (sizeof(complex) ); //在堆上进行申请空间不会调用构造函数
free(t1);
*/
/*
complex *t1 = new complex (1,2) ;
complex *t2 = new complex (1,2) ;
complex *t3 = new complex;
show(*t1);
*t3=t1->add(*t2);
show(*t3);
delete(t1);
delete(t2);
delete(t3);
int *a = new int[10];
*/
/*
complex s1;
complex s2;
//cout<<complex::count<<endl;
s1.showstatic();
*/
//完善虚数类
return 0;
}
四.继承,多态,纯虚函数
继承:class 子类 : 修饰符 父类
public:公有继承
protected:所有都为保护
private:所有为私有
1.基类的私有成员变量,继承这个类也无法访问这个私有成员变量。private成员变量只在本类中可使用
2.protect和public的成员变量,在子类中也可访问
3.private继承的子类无法调用父类中public的方法和变量
4.私有成员被继承,它占用内存空间,不可见不可操作
5.在派生类中,不会用到基类的方法,名字遮蔽原则
基类和派生类的方法不会构成重载,名字相同就被遮蔽
#include <iostream>
using namespace std;
class People
{
public:
void setname(const char*name);
void setage(int age);
const char * getname();
int getage();
void display();
private:
int m_age;
const char * m_name;
};
void People::display()
{
cout<<"name= "<<getname()<<"\nage= "<<getage()<<endl;
}
void People::setname(const char * name){ m_name = name; }
void People::setage(int age){ m_age = age;}
const char * People::getname(){ return m_name;}
int People::getage(){ return m_age;}
class Student:public People //公有继承
{
public:
void setscore(float score);
float getscore();
private:
float m_score;
};
void Student::setscore(float score){ m_score = score;}
float Student::getscore(){ return m_score;}
class midStu:public Student
{
public:
void setrank(int rank);
int display();
private:
int m_rank;
};
void midStu::setrank(int rank){m_rank = rank;}
int midStu::display()
{
cout<<" name = "<<getname()<<"\n age = "<<getage()<<" \n score = "<<getscore()<<"\n rank = "<<m_rank <<endl;
}
int main ()
{
midStu stu1;
stu1.setname("xiangming");
stu1.setage(20);
stu1.setscore(90.0f);
stu1.setrank(5);
stu1.display();
People peo1;
peo1.setname("sb");
peo1.setage(18);
peo1.display();
return 0;
}
6.派生类的构造函数中允许调用基类的构造函数,但仅限于参数的初始化表
#include <iostream>
using namespace std;
class People
{
public:
People(int age,const char * name);
void show();
const char* getname();
int getage();
private:
int m_age;
const char * m_name;
};
People::People(int age,const char * name):m_name(name),m_age(age)
{
}
const char* People::getname(){ return m_name;}
int People::getage(){ return m_age;}
void People::show()
{
cout<<"name = "<<getname()<<"\nage = "<<getage()<<endl;
}
class Student:public People
{
public:
Student(const char * name,int age,float score);
void show();
private:
float m_score;
};
Student::Student(const char * name,int age,float score):People(age,name),m_score(score)
{}
void Student::show()
{
cout<<"name is"<<getname()<<",age is"<<getage()<<",age score "<<m_score<<endl;
}
int main()
{
Student stu1("xm",15,80.5f);
stu1.show() ;
stu1.People::show(); //调用父类的方法
return 0;
}
7.继承的构造函数和构析函数的调用顺序,ABCCBA
#include <iostream>
using namespace std;
class A
{
public:
A( )
{
cout<<"A constructor"<<endl;
}
~A()
{
cout<<"A disconstructor"<<endl;
}
};
class B:public A
{
public:
B()
{
cout<<"B constructor"<<endl;
}
~B()
{
cout<<"B disconstructor"<<endl;
}
};
class C:public B
{
public:
C()
{
cout<<"C constructor"<<endl;
}
~C()
{
cout<<"C disconstructor"<<endl;
}
};
int main()
{
C test;
return 0;
}
8.继承的构造函数的调用顺序,只和继承的顺序有关
#include <iostream>
using namespace std;
class BaseA
{
public :
BaseA(int a,int b);
~BaseA();
void show()
{
cout<<m_a<<" "<<m_b<<endl;
}
protected:
int m_a;
int m_b;
};
BaseA::BaseA(int a,int b):m_a(a),m_b(b)
{
cout<<"A constructor"<<endl;
}
BaseA::~BaseA()
{
cout<<"A disconstructor"<<endl;
}
class BaseB
{
public:
BaseB(int c,int d);
~BaseB();
void show()
{
cout<<m_c<<" "<<m_d<<endl;
}
protected:
int m_c;
int m_d;
};
BaseB::BaseB(int c,int d):m_c(c),m_d(d)
{
cout<<"B constructor"<<endl;
}
BaseB::~BaseB()
{
cout<<"B disconstructor"<<endl;
}
class C:public BaseB,public BaseA //
{
public:
C(int a,int b,int c,int d,int e);
~C();
void show()
{
BaseA::show();
BaseB::show();
cout<<m_a<<","<<m_b<<","<<m_c<<","<<m_d<<","<<m_e<<endl;
}
protected:
int m_e;
};
C::C(int a,int b,int c,int d,int e):BaseA(a,b),BaseB(c,d),m_e(e)
{
cout<<"C constructor"<<endl;
}
C::~C()
{
cout<<"C disconstructor"<<endl;
}
int main()
{
C obj(1,2,3,4,5);
obj.show();
return 0;
}
9.菱形继承,命名冲突
虚继承:派生类中只留下一份间接基类的成员 virtual
向上转型:只能把派生类对象赋值给基类对象
#include <iostream>
using namespace std;
class A
{
protected:
int m_a;
};
class B:virtual public A //虚继承
{
protected:
int m_b;
};
class C:virtual public A //虚继承
{
protected:
int m_c;
};
class D:public B,public C
{
public:
void seta(int a)
{
m_a = a; // m_a=a; 命名冲突
}
protected:
int m_d;
};
int main()
{
D d;
return 0;
}
#include <iostream>
using namespace std;
class A
{
public:
A(int a):m_a(a){}
void display()
{
cout<<"A:"<<m_a<<endl;
}
protected:
int m_a;
};
class B:public A
{
public:
B(int a,int b):A(a),m_b(b){}
void display()
{
cout<<"B:"<<m_a<<","<<m_b<<endl;
}
public:
int m_b;
};
class C
{
public:
C(int c):m_c(c){}
void display()
{
cout<<"C:"<<m_c<<endl;
}
protected:
int m_c;
};
class D:public B,public C
{
public:
D(int a,int b,int c,int d):B(a,b),C(c),m_d(d){}
void display()
{
cout<<"D:"<<m_a<<","<<m_b<<","<<m_c<<endl;
}
private:
int m_d;
};
int main()
{
A *pa= new A(1);
B *pb= new B(10,20);
C *pc= new C(30);
D *pd= new D(100,200,300,400);
pd->display();
pa = pd; //向上转型 只能把派生类对象赋值给基类对象
pa->display();
pa = pb; //向上转型
pa->display();
pc = pd;
pc->display();
float a = 10;
printf("%f\n",a);
return 0;
}
多态:一个接口,多种方法(代码的复用性)(一行相同的代码,实现不同的功能)
1.重写:子类的同名函数,遮蔽父类的同名函数
2.虚函数:在需要修饰的函数前加virtual
3.基类的指针只能调用基类的方法
#include <iostream>
using namespace std;
class people
{
public:
people(const char * name,int age);
virtual void display(); //虚函数
protected:
int m_age;
const char * m_name;
};
people::people(const char * name,int age):m_name(name),m_age(age) {}
void people::display()
{
cout<<m_name<<" age:"<<m_age<<endl;
}
class teacher :public people
{
public:
teacher(const char *name ,int age,int salary):people(name,age),m_salary(salary) {}
void display()
{
cout<<m_name<<" age:"<<m_age<<",salary :"<<m_salary<<endl;
}
protected:
int m_salary;
};
int main()
{
people *p = new people("xm",23);
p->display();
p = new teacher("xg",45,4000); //基类的指针只能调用基类的方法
p->display(); //多态
return 0;
}
4.虚函数指针和虚函数表
被命名为virtual 派生类中所有的同名函数,自动变为虚函数
#include <iostream>
using namespace std;
class Base
{
public :
virtual void func();
virtual void func(int);
};
void Base::func()
{
cout<<"void Base::func()"<<endl;
}
void Base::func(int n)
{
cout<<"void Base::func(int) \n";
}
class Derived :public Base
{
void func();
void func(char *);
};
void Derived::func()
{
cout<<"void Derived::func() \n";
}
void Derived::func(char *str)
{
cout<<"void Derived::func(char *str) \n";
}
int main()
{
Base *p= new Derived(); //创建一个基类指针指向子类对象
p->func();
p->func(10);
//p->func("hello");
return 0;
}
5.构成多态的条件
(1)必须存在继承关系
(2)继承关系中必须有同名的虚函数
(3)存在基类的指针,通过该指针,调用虚函数
必须是基类定义的函数才能实现,注意函数重载的区别和特点
纯虚函数 virtual = 0 ;
1.没有函数体
2.纯粹的函数声明
3.包含纯虚函数的类称为抽象类:无法实例化的类
4.抽象类称为模板类,一般作为基类存在
一个类想要实例化,就要将所有继承来的纯虚函数全部重写
#include <iostream>
using namespace std;
class Line //线
{
public:
Line(float len);
virtual float area() = 0; //此纯虚函数作为抽象模板存在,没有办法实例化
virtual float volume() = 0;
protected:
float m_len;
};
Line::Line(float len):m_len(len)
{
}
class Rec:public Line //矩形
{
public:
Rec(float len,float width);
float area();
protected:
float m_width ;
};
Rec::Rec(float len,float width):Line(len),m_width(width)
{
}
float Rec::area()
{
return m_width*m_len;
}
class Cubiod:public Rec //长方体
{
public:
Cubiod(float len,float width,float height);
float area();
float volume();
protected:
float m_height;
};
Cubiod::Cubiod(float len,float width,float height):Rec(len,width),m_height(height)
{
}
float Cubiod::area()
{
return m_height*m_len*2+m_len*m_width*2+m_width*m_height*2;
}
float Cubiod::volume()
{
return m_height*m_len*m_width;
}
class Cube:public Cubiod //正方体
{
public:
Cube(float len);
};
Cube::Cube(float len):Cubiod(len,len,len)
{
}
int main()
{
Line *p = new Cubiod(2,3,4);
cout<<"cubiod area: "<<p->area() <<endl;
cout<<"cubiod volume : "<<p->volume()<<endl;
p = new Cube(5);
cout<<"cube area: "<<p->area() <<endl;
cout<<"cube volume : "<<p->volume()<<endl;
return 0;
}
完善三维空间内的表面积和体积的项目(圆形和球,三角形和棱柱体)
注意点:
typeid()
tupeid(data Yype)
typeid(expression)
三目运算符(a>b a:b)=90; 常量不能作为左值
c语言默认const为外部连接,c++默认外部连接
引用(实际上占内存空间)
引用必须初始化,指针可以不初始化
重写:
1.在不同类内
2.关键字:virtual
3.参数列表:一样
重载:int swap(int a,int b) int swap(float a,float b)
1.在一个类内
2.关键字:只检查参数
3.参数列表:必须不一样