Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

c++ program based on Dogs. create a C++ GUI Interface in Studio 2012 which lets

ID: 3718914 • Letter: C

Question

c++ program based on Dogs.

create a C++ GUI Interface in Studio 2012 which lets a user enter the path name of an input file and an output file. The input file contains a list of dogs currently boarded, including a tracking number of the dog, the breed of dog boarded, and a daily charge for the dog. You should be able to click a button, and items in the input file are stored in a linked list and the nprint to output file. Also, a count of the number of items printed to the output file.

List of dogs with column headings. This listing should include the following:

dog tracking number;

breed of dog;

daily charge;

tracking # - int

breed - array

charge - double

poniter to next record

Explanation / Answer

#include <iostream>

// base abstract class. that is what we use as the interface

class Animal

{

public:

Animal(char const* name): m_name(name) {}

// this is required to properly delete virtual classes

virtual ~Animal() {}

// with this strange syntax we define an unimplemeted "interface" function

virtual void make_sound() = 0;

protected:

// shared data field

std::string m_name;

};

// derived class. that means that Dog is a more refined version of Animal

// you usually inherit from only a single base class

class Dog: public Animal

{

public:

// need to forward the constructor arguments

Dog(char const* name): Animal(name) {}

// here we implement the interface

void make_sound() override

{

std::cout << m_name << " the dog said: bork!" << std::endl;

}

// type-specific method

void wag()

{

std::cout << "*" << m_name << " wags*" << std::endl;

}

};

// same as above, but with a different implementation

class Cat: public Animal

{

public:

Cat(char const* name): Animal(name) {}

void make_sound() override

{

std::cout << m_name << " the cat said: mow!" << std::endl;

}

void purr()

{

std::cout << "*" << m_name << " purrs*" << std::endl;

}

};

// We can now use Animal as the general type

// There is runtime type information that allows this (dynamic dispatch)

void animal_sound(Animal& a)

{

// method called via the generic interface

a.make_sound();

// type information is still there, we can extract the original type by

// probing if dynamic cast works

auto d = dynamic_cast<Dog*>(&a);

if (d != nullptr)

d->wag();

auto c = dynamic_cast<Cat*>(&a);

if (c != nullptr)

c->purr();

}

// we can do static dispatch too, via templates (duck typing)

template <typename T>

void animal_sound_1(T& a)

{

a.make_sound();

// however, we can't easily access type information here without

// using specialization..

}

// ..and that's pretty much equivalent to overloading the function

// this works by making two different functions with internally mangled names

// for each argument combination

void animal_sound_2(Dog& a) { a.make_sound(); a.wag(); }

void animal_sound_2(Cat& a) { a.make_sound(); a.purr(); }

int main()

{

auto cat = Cat("kitty");

auto dog = Dog("puppy");

animal_sound(cat);

animal_sound(dog);

animal_sound_1(cat);

animal_sound_1(dog);

animal_sound_2(cat);

animal_sound_2(dog);

return 0;

}

02_animals.rs

// how we implement this on Rust..

// instead of a base class, we define a "trait"

// traits define a functionality a type must provide. they're rougly like interfaces

// unlike classes, traits don't contain any data

trait Animal

{

fn make_sound(&self);

}

// structs contain only the declared fields, no inheritance

// (derive can automagically implement some special traits)

#[derive(Clone)]

struct Dog

{

name: String,

}

// methods are not part of the struct, they can be appended at any time

impl Dog

{

// rust types have only one constructor, the default one (used below)

// but it's common to create a "new" function for that purpose

fn new(name: &str) -> Self

{

// to_owned copies the borrowed string (&str) into a owned String

Dog{ name: name.to_owned() }

}

fn wag(&self)

{

println!("*{} wags*", self.name);

}

}

// now, we say that "Dog is an Animal" by implementing the corresponding trait

// there is no hierarchy, and a type can implement multiple traits

impl Animal for Dog

{

fn make_sound(&self)

{

println!("{} the dog said: bork!", self.name);

}

}

// now the same, but with Cat

#[derive(Clone)]

struct Cat

{

name: String,

}

impl Cat

{

fn new(name: &str) -> Self

{

Cat{ name: name.to_owned() }

}

fn purr(&self)

{

println!("*{} purrs*", self.name);

}

}

impl Animal for Cat

{

fn make_sound(&self)

{

println!("{} the cat said: mow!", self.name);

}

}

// we can use Animal as a "trait object", that means dynamic dispatch

// there is only 1 copy of this function

// but this isn't the best method..

fn animal_sound(a: &Animal)

{

a.make_sound();

// however type information is erased ..

}

// static dispatch is done via generics. it's similar to templates but it requires

// a "trait bound", that means only Animal methods are accessible from here.

// the compiler creates two copies of this function, one for each type

// (with `T: Animal + ?Sized` it allows both static and dynamic dispatch from the same function)

fn animal_sound_1<T: Animal>(a: &T)

{

a.make_sound();

// no type information here too ..

}

// .. to preserve type information, we use a enum (sum type, also called ADT)

enum AnyAnimal

{

Dog(Dog),

Cat(Cat),

}

// since it's the sum of two animals, it should be an Animal too

impl Animal for AnyAnimal

{

fn make_sound(&self)

{

// to use an enum, we extract it's data via a "match" statement

match *self

{

AnyAnimal::Dog(ref d) => d.make_sound(),

AnyAnimal::Cat(ref c) => c.make_sound(),

}

}

}

// now we got an heterogeneous type with full type information

fn animal_sound_2(a: AnyAnimal)

{

a.make_sound();

match a

{

AnyAnimal::Dog(d) => d.wag(),

AnyAnimal::Cat(c) => c.purr(),

}

}

// we can make things more transparent to the user by implementing the From trait

impl From<Dog> for AnyAnimal

{

fn from(dog: Dog) -> Self

{

AnyAnimal::Dog(dog)

}

}

impl From<Cat> for AnyAnimal

{

fn from(cat: Cat) -> Self

{

AnyAnimal::Cat(cat)

}

}

// "Into" is the counterpart of From

fn animal_sound_3<T: Into<AnyAnimal>>(anim: T)

{

let a = anim.into(); // run the conversion and extract the AnyAnimal

a.make_sound();

match a

{

AnyAnimal::Dog(d) => d.wag(),

AnyAnimal::Cat(c) => c.purr(),

}

}

fn main()

{

let cat = Cat::new("kitty");

let dog = Dog::new("puppy");

animal_sound(&cat);

animal_sound(&dog);

animal_sound_1(&cat);

animal_sound_1(&dog);

// using the enum directly is verbose

animal_sound_2(AnyAnimal::Cat(cat.clone()));

animal_sound_2(AnyAnimal::Dog(dog.clone()));

// using Into arguments makes it prettier

animal_sound_3(cat);

animal_sound_3(dog);

}

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Chat Now And Get Quote