「仮想関数」(2022/11/11 (金) 18:18:45) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
*仮想関数
**仮想関数
スーパークラス側の関数の前に「virtual」とつけることによって、前章の問題は解決します。
前に「virtual」とついた関数のことを仮想関数と呼びます。
仮想関数をオーバーライドした場合、派生クラスの関数が優先されて呼び出されます。
/*--------------Person.hの中身----------------*/
#pragma once
#include < string >
using namespace std;
class Person{
protected:
string name; // 名前
int age; // 年齢
public:
Person(string name, int age); // コンストラクタ
virtual ~Person(); // デストラクタ
virtual void SelfIntroduction() // 自己紹介(仮想関数)
};
/*--------------Student.hの中身----------------*/
#pragma once
#include "Person.h"
class Student : public Person {
protected:
int id; // 学籍番号
public:
Student(string name, int age, int id); // コンストラクタ
~Student(); // デストラクタ
void SelfIntroduction() // 自己紹介(オーバーライド)
int GetID(); // 学籍番号のゲッター
};
/*--------------main.cppの中身----------------*/
#include "Student.h"
int main(){
Person *satou = new Person("佐藤", 69); // Personクラス
Student *suzuki = new Student("鈴木", 24, 241035); // Studentクラス
satou->SelfIntroduction(); // 自己紹介(Person)
suzuki->SelfIntroduction(); // 自己紹介(Student)
delete satou;
delete suzuki;
return 0;
}
**純粋仮想関数
仮想関数は何かしらの定義を持ちましたが、
定義を持たない仮想関数を作ることもできます。
これを純粋仮想関数と呼び、以下のように = 0 をつけることで実現します。
virtual void SelfIntroduction() = 0;
上のように書くことで定義がないことを表しています。
オーバーライドしなければ使えません。
この純粋仮想関数のみで構成されたクラスを、抽象クラスまたはインターフェースクラスと呼びます。
インターフェースクラスは関数の定義を持っていないため、オブジェクトを作ることができません。
Person *satou = new Person("佐藤", 69); // Personクラス【エラー】
必ず継承し、関数を再定義して使うのです。
機能の宣言のみを持ったインターフェースですが、どのようなメリットがあるかつかみにくいと思います。
多態性の章において、基底クラスのポインタには、その派生クラスであればどんなオブジェクトでも扱うことができると書きました。
インターフェースはクラス階層の土台に位置し、抽象的な宣言のみ行います。
クラス使用者はインターフェースのみ知っていれば機能を使うことができる上
インターフェースから派生した様々なオブジェクトを同じコードで処理することができます。
例
図形の面積を求めるサンプルです。
抽象クラスShapeを用意し
そこから派生したRectクラス、Circleクラスでそれぞれ面積の計算方法を定義します。
/*--------------Shape.hの中身----------------*/
#pragma once
class Shape{
public:
Shape();
virtual ~Shape();
virtual double getArea() = 0;
};
/*--------------Shape.cppの中身----------------*/
#include "Shape.h"
Shape::Shape(){
}
Shape::~Shape(){
}
/*--------------Rect.hの中身----------------*/
#pragma once
#include "shape.h"
class Rect : public Shape {
private:
double width;
double height;
public:
Rect(double width, double height);
~Rect();
double getArea();
};
/*--------------Rect.cppの中身----------------*/
#include "Rect.h"
Rect::Rect(double width, double height){
this->width = width;
this->height = height;
}
Rect::~Rect(){
}
double Rect::getArea(){
return this->height * this->width;
}
/*--------------Circle.hの中身----------------*/
#pragma once
#include "shape.h"
class Circle : public Shape {
private:
double radius;
public:
Circle(double radius);
~Circle();
double getArea();
};
/*--------------Circle.cppの中身----------------*/
#include "Circle.h"
// M_PIを使うのに必要
#define _USE_MATH_DEFINES
#include <Math.h>
Circle::Circle(double radius) {
this->radius = radius;
}
Circle::~Circle(){
}
double Circle::getArea(){
return this->radius * this->radius * M_PI;
}
/*--------------main.cppの中身----------------*/
#include < iostream >
#include "Rect.h"
#include "Circle.h"
using namespace std;
int main() {
Shape* sikaku = new Rect(20, 30); // 四角
Shape* maru = new Circle(20); // 円
cout << "四角:" << sikaku->getArea() << endl;
cout << "円 :" << maru->getArea() << endl;
delete sikaku;
delete maru;
return 0;
}
*問題
**問題1
①「社員」クラスを作り、「働く」という純粋仮想関数を宣言せよ。
②「社員」クラスを継承し「社長」「部長」「営業」クラスを作り、それぞれ中身の異なる「働く」を定義せよ。
③mainで「社員」配列を用意して、「社長」「部長」「営業」のオブジェクトを配列に入れよ。
④社員配列をforループで回し、社員全員に「働く」関数を実行させよ。
*仮想関数
**仮想関数
スーパークラス側の関数の前に「virtual」とつけることによって、前章の問題は解決します。
前に「virtual」とついた関数のことを仮想関数と呼びます。
仮想関数をオーバーライドした場合、派生クラスの関数が優先されて呼び出されます。
/*--------------Person.hの中身----------------*/
#pragma once
#include < string >
using namespace std;
class Person{
protected:
string name; // 名前
int age; // 年齢
public:
Person(string name, int age); // コンストラクタ
virtual ~Person(); // デストラクタ
virtual void SelfIntroduction(); // 自己紹介(仮想関数)
};
/*--------------Student.hの中身----------------*/
#pragma once
#include "Person.h"
class Student : public Person {
protected:
int id; // 学籍番号
public:
Student(string name, int age, int id); // コンストラクタ
~Student(); // デストラクタ
void SelfIntroduction() // 自己紹介(オーバーライド)
int GetID(); // 学籍番号のゲッター
};
/*--------------main.cppの中身----------------*/
#include "Student.h"
int main(){
Person *satou = new Person("佐藤", 69); // Personクラス
Student *suzuki = new Student("鈴木", 24, 241035); // Studentクラス
satou->SelfIntroduction(); // 自己紹介(Person)
suzuki->SelfIntroduction(); // 自己紹介(Student)
delete satou;
delete suzuki;
return 0;
}
**純粋仮想関数
仮想関数は何かしらの定義を持ちましたが、
定義を持たない仮想関数を作ることもできます。
これを純粋仮想関数と呼び、以下のように = 0 をつけることで実現します。
virtual void SelfIntroduction() = 0;
上のように書くことで定義がないことを表しています。
オーバーライドしなければ使えません。
この純粋仮想関数のみで構成されたクラスを、抽象クラスまたはインターフェースクラスと呼びます。
インターフェースクラスは関数の定義を持っていないため、オブジェクトを作ることができません。
Person *satou = new Person("佐藤", 69); // Personクラス【エラー】
必ず継承し、関数を再定義して使うのです。
機能の宣言のみを持ったインターフェースですが、どのようなメリットがあるかつかみにくいと思います。
多態性の章において、基底クラスのポインタには、その派生クラスであればどんなオブジェクトでも扱うことができると書きました。
インターフェースはクラス階層の土台に位置し、抽象的な宣言のみ行います。
クラス使用者はインターフェースのみ知っていれば機能を使うことができる上
インターフェースから派生した様々なオブジェクトを同じコードで処理することができます。
例
図形の面積を求めるサンプルです。
抽象クラスShapeを用意し
そこから派生したRectクラス、Circleクラスでそれぞれ面積の計算方法を定義します。
/*--------------Shape.hの中身----------------*/
#pragma once
class Shape{
public:
Shape();
virtual ~Shape();
virtual double getArea() = 0;
};
/*--------------Shape.cppの中身----------------*/
#include "Shape.h"
Shape::Shape(){
}
Shape::~Shape(){
}
/*--------------Rect.hの中身----------------*/
#pragma once
#include "shape.h"
class Rect : public Shape {
private:
double width;
double height;
public:
Rect(double width, double height);
~Rect();
double getArea();
};
/*--------------Rect.cppの中身----------------*/
#include "Rect.h"
Rect::Rect(double width, double height){
this->width = width;
this->height = height;
}
Rect::~Rect(){
}
double Rect::getArea(){
return this->height * this->width;
}
/*--------------Circle.hの中身----------------*/
#pragma once
#include "shape.h"
class Circle : public Shape {
private:
double radius;
public:
Circle(double radius);
~Circle();
double getArea();
};
/*--------------Circle.cppの中身----------------*/
#include "Circle.h"
// M_PIを使うのに必要
#define _USE_MATH_DEFINES
#include <Math.h>
Circle::Circle(double radius) {
this->radius = radius;
}
Circle::~Circle(){
}
double Circle::getArea(){
return this->radius * this->radius * M_PI;
}
/*--------------main.cppの中身----------------*/
#include < iostream >
#include "Rect.h"
#include "Circle.h"
using namespace std;
int main() {
Shape* sikaku = new Rect(20, 30); // 四角
Shape* maru = new Circle(20); // 円
cout << "四角:" << sikaku->getArea() << endl;
cout << "円 :" << maru->getArea() << endl;
delete sikaku;
delete maru;
return 0;
}
*問題
**問題1
①「社員」クラスを作り、「働く」という純粋仮想関数を宣言せよ。
②「社員」クラスを継承し「社長」「部長」「営業」クラスを作り、それぞれ中身の異なる「働く」を定義せよ。
③mainで「社員」配列を用意して、「社長」「部長」「営業」のオブジェクトを配列に入れよ。
④社員配列をforループで回し、社員全員に「働く」関数を実行させよ。
表示オプション
横に並べて表示:
変化行の前後のみ表示: