强化有关C++的函数基础运用方法

知识点1【强化训练字符串类String】
知识点2【继承和派生的概述】(了解)1-2
继承的优点:减少代码的冗余  提高代码的重用性
知识点3【继承的格式】
继承方式分类:
父类个数分类:
注意:
案例1:公有继承 public
总结:
案例2:保护继承protected
总结: protected继承
案例3:私有继承 private
总结:private私有继承
总结:
知识点4【继承的内层结构】(了解)(vs studio)
知识点5【继承中的构造和析构的顺序】
总结:
知识点6【子类中 有父类、对象成员 构造和析构的顺序】
总结:(重要)
知识点7【详解 子类中的构造】
1、子类会默认调用  父类的 无参构造
2、子类 必须显示 使用初始化列表  调用 父类的有参构造
知识点8【父类和子类的同名 成员变量 处理】
1、当 父类和子类 成员变量同名时  在子类就近原则 选择本作用域的子类成员
2、如果在子类中 必须使用父类中的同名成员  必须加上父类的作用域。
3、子类可以借助 父类的公有方法 间接的操作 父类的私有数据(不可见的数据)
知识点9【父类和子类的同名 成员函数 处理】
案例:1子类继承父类所有成员函数 和成员变量
案例2:子类和父类 同名成员函数

知识点1【强化训练字符串类String】

mystring.h

#ifndef
MYSTRING_H #define MYSTRING_H #include using namespace std;
class MyString {     friend ostream&
operator<<(ostream &out, MyString &ob);     friend istream&
operator>>(istream &in, MyString &ob); private:     char *str;     int size; public:     MyString();     MyString(const char *str);     MyString(const MyString &ob);     ~MyString();     int Size(void);      //重载[]     char& operator[](int index);     //重载= 参数是对象     MyString&
operator=(const MyString &ob);     //重载= 参数是字符串常量 
const char *     MyString&
operator=(const char *str);      //重载+运算符    
MyString& operator+(const MyString &ob);     MyString& operator+(const char
*str);      //重载运算符     bool operator(const
MyString &ob);     bool
operator==(const char *str);  };  #endif // MYSTRING_H

mystring.cpp

#include
“mystring.h” #include<string.h> #include using
namespace std; MyString::MyString() {    
this->str = NULL;    
this->size = 0;    
cout<<“无参构造”<<endl; }  MyString::MyString(const char *str) {     cout<<“char *构造函数”<<endl;     //申请空间     this->str = new
char[strlen(str)+1];     //拷贝字符串     strcpy(this->str,
str);      //更新size     this->size = strlen(str); }  MyString::MyString(const MyString &ob)
{     cout<<“拷贝构造函数”<<endl;     //申请空间     this->str = new
char[strlen(ob.str)+1];     //拷贝字符串     strcpy(this->str,
ob.str);      //更新size     this->size =
ob.size; }  MyString::~MyString() {     cout<<“析构函数”<<endl;    
if(this->str != NULL)    
{         delete []
this->str;         this->str =
NULL;     } }  int MyString::Size() {     return this->size; }  char& MyString::operator[](int
index)//index表示数组的下标 {     //判断下标是否合法     if(index >=0 && index <
this->size)     {         return this->str[index];     }    
else     {         cout<<“index无效”<<endl;     } }  MyString &MyString::operator=(const
MyString &ob) {     //将ob.str拷贝到 this->str里面     //1、将this->str指向的旧空间 释放掉     if(this->str != NULL)     {        
delete [] this->str;        
this->str = NULL;     }      //根据ob.str的大小申请空间     this->str = new
char[ob.size+1];     strcpy(this->str,
ob.str);      this->size =
ob.size;      return *this; }  MyString &MyString::operator=(const char
*str) {     //1、将this->str指向的旧空间
释放掉     if(this->str
!= NULL)     {         delete [] this->str;         this->str = NULL;     }     
this->str = new char[strlen(str)+1];     strcpy(this->str, str);     this->size = strlen(str);     return *this; }  MyString& MyString::operator+(const
MyString &ob) {     //this 指向的是str5  ob是str6的别名    
//计算将来两个字符串拼接后的长度     int newSize = this->size + ob.size
+1;     char *tmp_str = new
char[newSize];     //清空tmp_str所指向的空间     memset(tmp_str,0,newSize);      //先将this->str拷贝到 tmp_str中 然后将ob.str追加到tmp_str中    
strcpy(tmp_str,this->str);    
strcat(tmp_str,ob.str);     
static MyString newString(tmp_str);    
//释放tmp_str指向的临时空间     if(tmp_str != NULL)     {        
delete [] tmp_str;         tmp_str
= NULL;     }      return newString; }  MyString &MyString::operator+(const char
*str) {     //计算将来两个字符串拼接后的长度     int newSize =
this->size + strlen(str) +1;     char
*tmp_str = new char[newSize];     //清空tmp_str所指向的空间     memset(tmp_str,0,newSize);      //先将this->str拷贝到 tmp_str中 然后将str指向的字符串 追加到tmp_str中    
strcpy(tmp_str,this->str);    
strcat(tmp_str,str);      static
MyString newString(tmp_str);     //释放tmp_str指向的临时空间     if(tmp_str != NULL)     {        
delete [] tmp_str;         tmp_str
= NULL;     }      return newString; }  bool MyString::operator==(const MyString
&ob) {     if( (strcmp(this->str,
ob.str) == 0) && (this->size == ob.size))     {    
    return true;     }     
return false; }  bool
MyString::operator==(const char *str) {    
if( (strcmp(this->str, str) == 0) && (this->size ==
strlen(str)))     {         return true;     }     
return false; } ostream& operator<<(ostream &out, MyString
&ob) {     out<<ob.str;//访问了ob中的私有数据 必须设置成友元     return out; }  istream& operator>>(istream
&in, MyString &ob) {     //记得将原有的数据清楚     if(ob.str != NULL)     {        
delete [] ob.str;         ob.str
=NULL;     }      //获取键盘输入的字符串     char buf[1024]="";//临时buf     in >> buf;//先得到键盘输入的数据  然后根据buf的实际大小
开辟空间      ob.str = new
char[strlen(buf)+1];     strcpy(ob.str,
buf);     ob.size = strlen(buf);      return in; }

main.cpp

#include
#include"mystring.h" using namespace std;  int main(int argc, char *argv[]) {     MyString str1(“hehe”);     //自定义对象 必须重载<<
(普通全局友元函数实现)    
cout<<str1<<endl;    
cout<<"size = "<<str1.Size()<<endl;      //自定义对象 必须重载>>
(普通全局友元函数实现)    
cin>>str1;    
cout<<str1<<endl;    
cout<<"size = “<<str1.Size()<<endl;      MyString str2(“hello
class”);     //重载[]运算符    
cout<<str2[1]<<endl;     
//重载[]运算符 返回值必须是左值 才能写操作     //重载[]运算符 的返回值必须是引用     str2[1] =‘E’;     cout<<str2<<endl;      MyString str3(“hello
str3”);     cout<<“str3:”<<str3<<endl;      //将对象str2 赋值
给str3     //(默认赋值语句
浅拷贝)     //必须重载=运算符(成员函数完成)     str3 = str2;    
cout<<“str3:”<<str3<<endl;      MyString str4(“hello str4”);    
cout<<“str4:”<<str4<<”, size =
“<<str4.Size()<<endl;    
//必须重载=运算符(成员函数完成)     str4=“hello string”;    
cout<<“str4:”<<str4<<”, size =
"<<str4.Size()<<endl;     
//重载+运算符     MyString str5(“我爱大家”);     MyString
str6(“我爱千锋”);     cout<<str5+str6<<endl;      MyString str7(“大家爱我”);     cout<<
str7+“千锋爱我”<<endl;      //重载==运算符     MyString
str8(“hehe”);     MyString
str9(“haha”);     if(str8 == str9)     {        
cout<<“相等”<<endl;     }    
else     {         cout<<“不相等”<<endl;     }      if(str8 == “hehe”)     {        
cout<<“相等”<<endl;     }    
else     {         cout<<“不相等”<<endl;     }       return 0; }

运行结果:

知识点2【继承和派生的概述】(了解)1-2

继承的优点:减少代码的冗余  提高代码的重用性

知识点3【继承的格式】

派生类定义格式:
   Class 派生类名 :  继承方式 基类名{          //派生类新增的数据成员和成员函数    };    class
子类: 继承方式  父类名{        //子类新增的数据成员和成员函数    };

继承方式分类:

public : 公有继承   (重要)

private : 私有继承

protected : 保护继承

父类个数分类:

单继承:指每个派生类只直接继承了一个基类的特征   (一个父类 派生出 一个子类)

多继承:指多个基类派生出一个派生类的继承关系,多继承的派生类直接继承了不止一个基类的特征(多个父类  派生出 一个子类)

注意:

子类继承父类,子类拥有父类中全部成员变量和成员方法(除了构造和析构之外的成员方法),但是在子类中,继承的成员并不一定能直接访问,不同的继承方式会导致不同的访问权限。

案例1:公有继承 public

//设置一个父类 class Base { public:     int
a; private:     int b; protected:     int
c; };  //设置一个子类
class Son:public Base { public:     //父类中的public数据 
在子类中 也是public    
//父类中的private数据 在子类中 是不可见的     //父类中的protected数据 在子类中 是protected的     //子类的内部     void showSon()     {        
//b = 200;//不能直接访问         c =300;//在子类 内部是可以访问的     } }; 
void test01() {     //子类的外部     Son ob;     ob.a = 100;     cout<<"父类中的public数据a =
"<<ob.a<<endl;     
//ob.b = 200;//在子类外 访问不了     //ob.c = 200;//在子类外 访问不了  }

总结:

父类中的public数据  在子类中 也是public

父类中的private数据
在子类中 是不可见的

父类中的protected数据 在子类中 是protected的

(public 继承  父类中的私有数据 在子类 不可见 其他保持原样)

案例2:保护继承protected

//保护继承 class Son1:protected Base { private:  public:    
//父类中的public数据  在子类中 也是protected     //父类中的private数据
在子类中 是不可见的     //父类中的protected数据 在子类中 是protected的     //子类的内部     void showbase(){         a = 100;//子类内部可访问         //b = 200;//不能直接访问         c = 300;//子类内部可访问     } }; void test02() {     Son1 ob;     //ob.a;//子类外不可访问     //ob.b;//子类外不可访问     //ob.c;//子类外不可访问 }

总结: protected继承

父类中的public数据 
在子类中 也是protected

父类中的private数据 在子类中 是不可见的

父类中的protected数据
在子类中 是protected的

(保护继承  父类的私有数据 在子类中 不可见  其他数据 都变保护)

案例3:私有继承 private

//保护继承 class Son2:private Base { private: 
public:     //父类中的public数据 
在子类中 也是private     //父类中的private数据
在子类中 是不可见的     //父类中的protected数据 在子类中 是private的     //子类的内部     void showbase(){         a = 100;//子类内部可访问         //b = 200;//不能直接访问         c = 300;//子类内部可访问     } }; void test03() {     Son2 ob;     //ob.a;//子类外不可访问     //ob.b;//子类外不可访问     //ob.c;//子类外不可访问 }

总结:private私有继承

父类中的public数据  在子类中 也是private

父类中的private数据
在子类中 是不可见的

父类中的protected数据
在子类中 是private的

(私有继承  父类中的私有数据在子类中 不可见  其他变成私有)

总结:

不管啥继承方式:父类中的私有数据在 子类中不可见

知识点4【继承的内层结构】(了解)(vs studio)

class Base {
public:     int a; protected:     int b; private:     int c; }; 
class Son :public Base { public:    
int d;     int e; }; int main(int
argc, char* argv[]) {     cout <<
sizeof(Son) << endl;     return 0;
}

步骤:

cl /d1
reportSingleClassLayoutSon test.cpp

Son类的布局:

知识点5【继承中的构造和析构的顺序】

class Base {
public:     Base()    
{         cout<<“父类的无参构造函数”<<endl;     }     ~Base()    
{         cout<<“父类中的析构函数”<<endl;     } };
class Son:public Base { public:    
Son()     {         cout<<“子类的无参构造”<<endl;     }     ~Son()    
{         cout<<“子类中的析构函数”<<endl;     } }; void
test01() {     Son ob1; }

运行结果:

总结:

构造顺序: 父类(基类)构造 ------> 子类(派生类)构造

析构顺序:子类(派生类)析构------> 父类 (基类) 析构

知识点6【子类中 有父类、对象成员 构造和析构的顺序】

父类的构造和析构      对象成员的构造和析构     子类自身的构造和析构

总结:(重要)

class Other
{ public:     Other()     {        
cout<<“对象成员的构造函数”<<endl;     }    
~Other()     {         cout<<“对象成员的析构函数”<<endl;     } };
class Base { public:     Base()     {        
cout<<“父类的无参构造函数”<<endl;     }    
~Base()     {         cout<<“父类中的析构函数”<<endl;     } };
class Son:public Base { public:    
Son()     {         cout<<“子类的无参构造”<<endl;     }     ~Son()    
{         cout<<“子类中的析构函数”<<endl;     }      Other ob;//对象成员  }; void test01() {     Son ob1; }

运行结果:

知识点7【详解 子类中的构造】

1、子类会默认调用  父类的 无参构造

2、子类 必须显示 使用初始化列表  调用 父类的有参构造

调用形式:父类名称。

Son(int
a,int b):Base(a),b(b) {     //this->b
= b; }

class Base {
private:     int a; public:      Base()    
{         cout<<“父类的无参构造函数”<<endl;     }     Base(int a)     {        
this->a = a;        
cout<<“父类的有参构造函数”<<endl;     }    
~Base()     {         cout<<“父类中的析构函数”<<endl;     } };
class Son:public Base { private:     int
b; public:     Son()     {        
cout<<“子类的无参构造”<<endl;     }    
Son(int b)     {         this->b = b;         cout<<“子类的有参构造函数int”<<endl;    
}      //子类必须用 初始化列表 显示的调用父类的有参构造     //父类名称(参数)    
Son(int a,int b):Base(a)//显示的调用父类的有参构造     {        
this->b = b;        
cout<<“子类的有参构造函数 int
int”<<endl;     }     ~Son()    
{         cout<<“子类中的析构函数”<<endl;     } };
void test01() {     //子类 默认 会调用 父类的无参构造     //Son ob1(10);      //子类必须用 初始化列表 显示的调用父类的有参构造     //父类名称+()     Son ob2(10,20);  }

运行结果:

案例提高:

如果父类有参构造:

Base(int a, int data) {     this->a = a;     this->data = data;     cout<<“父类的有参构造函数”<<endl; }

子类想调用 父类有参构造:

//子类必须用
初始化列表 显示的调用父类的有参构造 //父类名称(参数) Son(int a,int b, int c):Base(a,c),b(b)//显示的调用父类的有参构造 {     //this->b = b;     cout<<“子类的有参构造函数 int int”<<endl; }

知识点8【父类和子类的同名 成员变量 处理】

1、当 父类和子类 成员变量同名时  在子类就近原则 选择本作用域的子类成员

2、如果在子类中 必须使用父类中的同名成员  必须加上父类的作用域。

class Base
{     //父类的私有数据 一旦涉及继承 在子类中不可见 public:     int num; public:     Base(int num)     {        
this->num = num;        
cout<<“Base有参构造int”<<endl;     }    
~Base()     {         cout<<“析构函数”<<endl;     }
};  class Son:public Base { private:     int num; public:     Son(int num1,int num2):Base(num1)     {    
    this->num = num2;         cout<<“有参构造int int”<<endl;    
}      ~Son()     {        
cout<<“析构函数”<<endl;     }    
void showNum(void)     {         //如果在子类中 必须使用父类中的同名成员  必须加上父类的作用域         cout<<"父类中的num = "<<Base::num<<endl;          //当 父类和子类 成员变量同名时  在子类就近原则 选择本作用域的子类成员         cout<<"子类中的num = "<<num<<endl;     } }; 
void test01() {     Son
ob1(10,20);     ob1.showNum(); }

运行结果:

3、子类可以借助 父类的公有方法 间接的操作 父类的私有数据(不可见的数据)

class Base
{  private:     int num;//父类的私有数据 一旦涉及继承 在子类中不可见 public:     Base(int
num)     {         this->num = num;         cout<<“Base有参构造int”<<endl;    
}     ~Base()     {        
cout<<“析构函数”<<endl;     }    
int getNum(void)     {         return num;     } }; 
class Son:public Base { private:    
int num; public:     Son(int num1,int
num2):Base(num1)     {         this->num = num2;         cout<<“有参构造int int”<<endl;    
}      ~Son()     {        
cout<<“析构函数”<<endl;     }    
void showNum(void)     {         //如果在子类中 必须使用父类中的同名成员  必须加上父类的作用域         cout<<"父类中的num = "<<getNum()<<endl;          //当 父类和子类 成员变量同名时  在子类就近原则 选择本作用域的子类成员         cout<<"子类中的num = "<<num<<endl;     } }; 
void test01() {     Son
ob1(10,20);     ob1.showNum(); }

运行结果:

知识点9【父类和子类的同名 成员函数 处理】

案例:1子类继承父类所有成员函数 和成员变量

class Base {
public:     void func(void)     {        
cout<<“父类中的void
func”<<endl;     }     void func(int a)     {        
cout<<"父类中的int func a =
"<<a<<endl;     }
};  class Son:public Base { public:      }; 
void test01() {     //为啥构造和析构除外?父类的构造和析构 只有父类自己知道该怎么做(构造和析构 系统自动调用)     //子类会继承父类所有成员函数(构造和析构函数除外) 和成员变量    
Son ob1;     ob1.func();//访问的是父类的void func(void)    
ob1.func(10);//访问的是父类的func(int a) }

案例2:子类和父类 同名成员函数

class Base {
public:     void func(void)     {        
cout<<“父类中的void
func”<<endl;     }     void func(int a)     {        
cout<<"父类中的int func a =
"<<a<<endl;     }
};  class Son:public Base { public:     //一旦子类 实现了 父类的同名成员函数 将屏蔽所有父类同名成员函数     void func(void)     {        
cout<<“子类中voidfunc”<<endl;     } }; 
void test01() {     //为啥构造和析构除外?父类的构造和析构 只有父类自己知道该怎么做(构造和析构 系统自动调用)     //子类会继承父类所有成员函数(构造和析构函数除外) 和成员变量    
Son ob1;     ob1.func();     //ob1.func(10);//err //一旦子类 实现了 父类的同名成员函数
将屏蔽所有父类同名成员函数       //如果用户
必须要调用父类 的同名成员函数 必须加作用域    
ob1.Base::func();//调用父类的void func     ob1.Base::func(10);//调用父类的int func } int main(int argc, char *argv[]) {     test01();     return 0; }

运行结果:

发布了1 篇原创文章 · 获赞 0 · 访问量 82

猜你喜欢

转载自blog.csdn.net/zeminglin/article/details/105108140